SimonTestNet/SimonTest

Cannot read property 'text' of undefined

Closed this issue · 3 comments

I am using the SimonTest (Extension) for VS Code. For some of the services or components, when I use the extension, it throws me the error "Cannot read property 'text' of undefined" Tried to research it, but I could not find a solution or why it could throw me that issue.
Is it possible for the next version to put some warnings which will be thrown and checked more easily for the specific issue or place!?
image

Thank you!

Can you post a small service or component to reproduce the error?
(remove everything not necessary to reproduce it)

Thanks

import { Component, Input } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';

import { PortfolioEntry } from 'client/model/portfolioEntry';
import { IFileUpload } from '../../../shared/models/interfaces';
import { NoIdentifier, WrongFileFormate, NoRequiredHeaders, RequiredHeadersHelper } from '../../models/default-values';

export interface IsValid {
passed: boolean;
fileName?: string,
errorMessage: string;
}

@component({
selector: 'csv-upload',
templateUrl: './csv-upload.component.html',
styleUrls: ['./csv-upload.component.scss'],
})
export class CSVUploadComponent {
@input() title: string;
@input() sampleFileHref: string;
@input() requiredColumns: string[];
@input() extraConstraint: string;
@input() checkParentValidation: (value: [string[], string[]]) => IsValid;

public files: IFileUpload[] = [];
public cvsData: PortfolioEntry[] = [];
public warningMessage: string;
public fileName: string = '';

public form: FormGroup = new FormGroup({
file: new FormControl(),
});

private uploadFiles: any;
private supportedFileTypes: string[] = [
'text/csv',
'text/x-csv',
'application/vnd.ms-excel',
'application/csv',
'application/x-csv',
'text/comma-separated-values',
'text/x-comma-separated-values',
'text/tab-separated-values',
];

private supportedExtensions: string[] = ['.csv'];

public fileBrowseHandler(files: any, input: any) {
this.warningMessage = '';

if (this.checkFileType(files)) {
  this.convertFile(input);
  this.uploadFiles = files;
} else {
  this.warningMessage = WrongFileFormate;
  this.form.get('file').reset();
}

}

public deleteFile(index: number) {
this.files.splice(index, 1);
}

private checkFileType(files: Partial[]): boolean {
for (let i = 0; i < files.length; i++) {
const f = files[i] as Partial;
this.fileName = f.name;
if (f.type === '') {
// If unable to determine MIME-type
// Use the file extension to verify supported format
const fileExtension = this.getFileExtension(f.name);
if (!this.supportedExtensions.includes(fileExtension)) {
return false;
}
} else {
// Otherwise, use MIME-type
if (!this.supportedFileTypes.includes(f.type)) {
return false;
}
}
}
return true;
}

private getFileExtension(fileName: string): string {
const lastPeriod = fileName.lastIndexOf('.');
if (lastPeriod === -1) return ''; // No extension, returning an empty string will mean it won't get matched to supported list
return fileName.substring(lastPeriod); // return rest of file name (should be extension)
}

/**

  • Convert upload files to string via FileReader

  • Possible for multiple file upload
    */
    private convertFile(input: any) {
    if (input.files && input.files[0]) {
    let files = input.files;
    let promises = [];

    // loop through upload files to be read, set file content as string
    // and store promises in array
    for (var i = 0; i < files.length; i++) {
    let file = files[i];
    let filePromise = new Promise((resolve) => {
    let reader = new FileReader();
    reader.readAsText(file);
    reader.onload = () => resolve(reader.result as string);
    });
    promises.push(filePromise);
    }

    // waits till all files have been read
    Promise.all(promises)
    .then((fileContents: string[]) => {
    let fileText: string = fileContents[0];

     // if there is more than one file, loop through the remaining files
     // removing their csv headers before joining all the content together.
     if (fileContents.length > 1) {
       for (let i = 1; i < fileContents.length; i++) {
         const data = fileContents[i].split('\n') as string[];
         const lines = data.filter((_, index) => index !== 0);
         fileText += lines.join('\n');
       }
     }
    
     // pass all files as a string to be validate correctly
     this.validateCSV(fileText);
    

    })
    .catch((error) => {
    this.warningMessage = File upload error ${error.message ? : \n ${error.message} : '.' }.;
    console.error(error.message);
    });
    }
    }

/**

  • Run validation checks on the CSV data.
    */
    private validateCSV(csvText?: string) {
    const data = csvText.split('\n') as string[];
    const headers: string[] = this.convertCSVHeadersToArray(data[0]);
    const lines = data.filter((_, index) => index !== 0); // remove the header at index 0
if (!this.checkFileHasRequiredHeaders(headers)) {
  this.warningMessage = `${NoRequiredHeaders} \n ${RequiredHeadersHelper} a ${this.requiredColumns.join(
    ' and ',
  )} column.`;
  return;
}

if (!this.checkRowHasIdentifyData(headers, lines)) {
  this.warningMessage = NoIdentifier;
  return;
}

const { passed, errorMessage } = this.checkParentValidation([lines, headers]);

if (!passed) {
  this.warningMessage = errorMessage;
  return;
}

// passed all validation
this.convertCSVtoJSON(lines, headers);
this.prepareFilesList(this.uploadFiles);

// reset control
this.form.get('file').reset();

}

/**

  • Check each row / company as at least one of the required identify filled.
    */
    private checkRowHasIdentifyData(headers: string[], lines: string[]): boolean {
    const tickerIndex = headers.findIndex(
    (item) => item === 'tickercode' || item === 'ticker',
    );
    const sedolIndex = headers.findIndex((item) => item === 'sedol');
    const isinIndex = headers.findIndex((item) => item === 'isin');
const checkEveryCompany = (line) => {
  const currentLine = line.split(',');
  const hasNoIdentify =
    currentLine[tickerIndex] === '' &&
    currentLine[sedolIndex] === '' &&
    currentLine[isinIndex] === '';

  return !hasNoIdentify;
};
return lines.every(checkEveryCompany);

}

/**

  • Check if upload has one of the 3 identifers and check if the file has
  • all of the other required columns.
    */
    private checkFileHasRequiredHeaders(headers: string[]): boolean {
    let hasKeyIdentifer = false;
    headers.forEach((val) => {
    if (IDENTIFERS.includes(val)) hasKeyIdentifer = true;
    });
    let hasShareValue = this.requiredColumns.every((val) =>
    headers.includes(val),
    );
    return hasKeyIdentifer && hasShareValue;
    }

private convertCSVHeadersToArray(csvHeader: string): string[] {
return csvHeader
.trim()
.split(',')
.map((w) => w.toLowerCase());
}

private convertCSVtoJSON(lines: string[], headers: string[]) {
let entry: PortfolioEntry[] = [];
for (let i = 0; i < lines.length; i++) {
// Ignore empty lines. Some CSV files can have a trailing line with no data.
if (lines[i].trim() === ',,,,' || !lines[i]) {
continue;
}

  let obj: PortfolioEntry = {};
  const currentLine = lines[i].split(',');
  for (let j = 0; j < headers.length; j++) {
    let header = headers[j].trim();
    // skip non required columns
    if (!this.checkIfRequiredColumns(header)) {
      continue;
    } else {
      if (header === 'shares' || header === 'value') {
        let num = currentLine[j] ? currentLine[j].replace('"', '') : '0';
        obj[header] = parseFloat(num);
      } else if (header === 'ticker' || header === 'tickercode') {
        // set ticker to correct key name for api
        obj.tickerCode = currentLine[j];
      } else {
        obj[header] = currentLine[j];
      }
    }
  }

  entry = [...entry, obj];
}

this.cvsData = [...this.cvsData, ...entry];

}

private checkIfRequiredColumns(header: string): boolean {
return IDENTIFERS.includes(header) || this.requiredColumns.includes(header);
}

private uploadFilesSimulator(index: number): void {
setTimeout(() => {
if (index === this.files.length) {
return;
} else {
const progressInterval = setInterval(() => {
// in case item gets deleted during progress interval
if (index === this.files.length || this.files.length === 0) {
return;
} else if (this.files[index].progress === 100) {
clearInterval(progressInterval);
this.uploadFilesSimulator(index + 1);
} else {
this.files[index].progress += 20;
if (index === this.files.length || this.files.length === 0) {
return;
}
}
}, 200);
}
}, 500);
}

/**

  • Convert Files list to normal array list
    */
    private prepareFilesList(files: IFileUpload[]) {
    for (const item of files) {
    item.progress = 0;
    this.files.push(item);
    }
    this.uploadFilesSimulator(0);
    }
    }

export const IDENTIFERS: string[] = ['isin', 'sedol', 'tickercode', 'ticker'];

Please update your SimonTest extension (to v1.9.10).

Thanks