Skip to content

Commit

Permalink
Bring SwissQuote converter under test
Browse files Browse the repository at this point in the history
  • Loading branch information
dickwolff authored Feb 1, 2024
2 parents 52a8664 + ad3ddd1 commit 36a115c
Show file tree
Hide file tree
Showing 17 changed files with 296 additions and 71 deletions.
46 changes: 46 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: frameworkTesting
run-name: Test Converters

on:
push:
branches:
- main
- feature/*
pull_request:
branches:
- main


jobs:
run-converter-tests:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: actions/checkout@v3

- uses: actions/setup-node@v3
with:
node-version: '20'

- run: npm install

- run: npm run test

- name: Convert code coverage results
uses: irongut/[email protected]
with:
filename: coverage/*.xml
badge: true
format: 'markdown'
output: 'file'

- name: Add code coverage PR comment
uses: marocchino/sticky-pull-request-comment@v2
if: github.event_name == 'pull_request'
with:
recreate: true
path: code-coverage-results.md

- name: Write to job summary
run: cat code-coverage-results.md >> $GITHUB_STEP_SUMMARY
15 changes: 15 additions & 0 deletions jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { Config } from '@jest/types';

// Sync object
const config: Config.InitialOptions = {
verbose: true,
testTimeout: 30000,
transform: {
'^.+\\.tsx?$': 'ts-jest'
},
coverageDirectory: 'coverage',
collectCoverageFrom: ['src/**/*.ts'],
coverageReporters: ['text', 'cobertura', 'html']
};

export default config;
10 changes: 7 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
{
"name": "trading212-to-ghostfolio",
"name": "export-to-ghostfolio",
"version": "1.0.0",
"description": "Convert Trading 212 export to Ghostfolio import",
"description": "Convert multiple broker exports to Ghostfolio import",
"main": "index.js",
"scripts": {
"start": "nodemon"
"start": "nodemon",
"test": "jest --coverage"
},
"author": "Dick Wolff",
"repository": {
"url": "https://github.com/dickwolff/Trading-212-to-Ghostfolio"
},
"license": "Apache-2.0",
"devDependencies": {
"@types/jest": "^29.5.11",
"@types/node": "^20.10.4",
"jest": "^29.7.0",
"nodemon": "^3.0.2",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.1",
"typescript": "^5.3.3"
},
Expand Down
31 changes: 26 additions & 5 deletions src/converters/abstractconverter.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as fs from "fs";
import * as cliProgress from "cli-progress";

export abstract class AbstractConverter {
Expand All @@ -14,21 +15,41 @@ export abstract class AbstractConverter {
cliProgress.Presets.shades_classic);
}

/**
* Read and process the file.
*
* @param inputFile The file to convert.
* @param successCallback A callback to execute after processing has succeeded.
* @param errorCallback A callback to execute after processing has failed.
*/
public readAndProcessFile(inputFile: string, successCallback: CallableFunction, errorCallback: CallableFunction) {

// If the file does not exist, throw error.
if (!fs.existsSync(inputFile)) {
return errorCallback(new Error(`File ${inputFile} does not exist!`));
}

const contents = fs.readFileSync(inputFile, "utf-8");

this.processFileContents(contents,successCallback, errorCallback);
}

/**
* Check if a record should be ignored from processing.
*
* @param record The record to check
* @returns true if the record should be skipped, false otherwise.
*/
abstract isIgnoredRecord(record: any): boolean;
abstract isIgnoredRecord(record: any): boolean;

/**
* Process an export file.
* Process export file contents.
*
* @param inputFile The file to convert.
* @param callback A callback to execute after processing has succeeded.
* @param input The file contents to convert.
* @param successCallback A callback to execute after processing has succeeded.
* @param errorCallback A callback to execute after processing has failed.
*/
abstract processFile(inputFile: string, callback: any): void;
abstract processFileContents(input: string, successCallback: CallableFunction, errorCallback: CallableFunction): void;

/**
* Retrieve headers from the input file.
Expand Down
13 changes: 13 additions & 0 deletions src/converters/degiroConverter.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { DeGiroConverter } from "./degiroConverter";

describe("degiroConverter", () => {

it("should construct", () => {

// Act
const sut = new DeGiroConverter();

// Asssert
expect(sut).toBeTruthy();
});
});
22 changes: 12 additions & 10 deletions src/converters/degiroConverter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import * as fs from "fs";
import dayjs from "dayjs";
import { parse } from "csv-parse";
import { DeGiroRecord } from "../models/degiroRecord";
Expand All @@ -24,25 +23,27 @@ export class DeGiroConverter extends AbstractConverter {
/**
* @inheritdoc
*/
public processFile(inputFile: string, callback: any): void {

// Read file contents of the CSV export.
const csvFile = fs.readFileSync(inputFile, "utf-8");
public processFileContents(input: string, successCallback: any, errorCallback: any): void {

// Parse the CSV and convert to Ghostfolio import format.
parse(csvFile, {
parse(input, {
delimiter: ",",
fromLine: 2,
columns: this.processHeaders(csvFile),
columns: this.processHeaders(input),
cast: (columnValue, context) => {

// Custom mapping below.

return columnValue;
}
}, async (_, records: DeGiroRecord[]) => {

// If records is empty, parsing failed..
if (records === undefined) {
return errorCallback(new Error("An error ocurred while parsing!"));
}

console.log(`[i] Read CSV file ${inputFile}. Start processing..`);
console.log("[i] Read CSV file. Start processing..");
const result: GhostfolioExport = {
meta: {
date: new Date(),
Expand Down Expand Up @@ -88,7 +89,8 @@ export class DeGiroConverter extends AbstractConverter {
this.progress);
}
catch (err) {
throw err;
this.logQueryError(record.isin || record.product, idx);
return errorCallback(err);
}

// Log whenever there was no match found.
Expand Down Expand Up @@ -232,7 +234,7 @@ export class DeGiroConverter extends AbstractConverter {

this.progress.stop()

callback(result);
successCallback(result);
});
}

Expand Down
13 changes: 13 additions & 0 deletions src/converters/degiroConverterV2.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { DeGiroConverterV2 } from "./degiroConverterV2";

describe("degiroConverter", () => {

it("should construct", () => {

// Act
const sut = new DeGiroConverterV2();

// Asssert
expect(sut).toBeTruthy();
});
});
6 changes: 3 additions & 3 deletions src/converters/degiroConverterV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export class DeGiroConverterV2 extends AbstractConverter {
/**
* @inheritdoc
*/
public processFile(inputFile: string, callback: any): void {
public processFileContents(inputFile: string, successCallback: any, errorCallback: any): void {

// Read file contents of the CSV export.
const csvFile = fs.readFileSync(inputFile, "utf-8");
Expand Down Expand Up @@ -101,7 +101,7 @@ export class DeGiroConverterV2 extends AbstractConverter {
}
catch (err) {
this.logQueryError(record.isin || record.product, idx);
throw err;
return errorCallback(err);
}

// Log whenever there was no match found.
Expand Down Expand Up @@ -145,7 +145,7 @@ export class DeGiroConverterV2 extends AbstractConverter {

this.progress.stop();

callback(result);
successCallback(result);
});
}

Expand Down
13 changes: 13 additions & 0 deletions src/converters/finpensionConverter.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { FinpensionConverter } from "./finpensionConverter";

describe("finpensionConverter", () => {

it("should construct", () => {

// Act
const sut = new FinpensionConverter();

// Asssert
expect(sut).toBeTruthy();
});
});
20 changes: 8 additions & 12 deletions src/converters/finpensionConverter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import * as fs from "fs";
import dayjs from "dayjs";
import { parse } from "csv-parse";
import { AbstractConverter } from "./abstractconverter";
Expand All @@ -21,16 +20,13 @@ export class FinpensionConverter extends AbstractConverter {
/**
* @inheritdoc
*/
public processFile(inputFile: string, callback: any): void {

// Read file contents of the CSV export.
const csvFile = fs.readFileSync(inputFile, "utf-8");
public processFileContents(input: string, successCallback: any, errorCallback: any): void {

// Parse the CSV and convert to Ghostfolio import format.
const parser = parse(csvFile, {
const parser = parse(input, {
delimiter: ";",
fromLine: 2,
columns: this.processHeaders(csvFile, ";"),
columns: this.processHeaders(input, ";"),
cast: (columnValue, context) => {

// Custom mapping below.
Expand Down Expand Up @@ -66,10 +62,10 @@ export class FinpensionConverter extends AbstractConverter {

// If records is empty, parsing failed..
if (records === undefined) {
throw new Error(`An error ocurred while parsing ${inputFile}...`);
return errorCallback(new Error("An error ocurred while parsing!"));
}

console.log(`Read CSV file ${inputFile}. Start processing..`);
console.log("[i] Read CSV file. Start processing..");
const result: GhostfolioExport = {
meta: {
date: new Date(),
Expand Down Expand Up @@ -124,7 +120,7 @@ export class FinpensionConverter extends AbstractConverter {
}
catch (err) {
this.logQueryError(record.isin || record.assetName, idx + 2);
throw err;
return errorCallback(err);
}

// Log whenever there was no match found.
Expand Down Expand Up @@ -163,7 +159,7 @@ export class FinpensionConverter extends AbstractConverter {

this.progress.stop()

callback(result);
successCallback(result);
});

// Catch any error.
Expand Down
6 changes: 3 additions & 3 deletions src/converters/schwabConverter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export class SchwabConverter extends AbstractConverter {
/**
* @inheritdoc
*/
public processFile(inputFile: string, callback: any): void {
public processFileContents(inputFile: string, successCallback: any, errorCallback: any): void {

// Read file contents of the CSV export.
const csvFile = fs.readFileSync(inputFile, "utf-8");
Expand Down Expand Up @@ -145,7 +145,7 @@ export class SchwabConverter extends AbstractConverter {
}
catch (err) {
this.logQueryError(record.symbol || record.description, idx + 2);
throw err;
return errorCallback(err);
}

// Log whenever there was no match found.
Expand Down Expand Up @@ -187,7 +187,7 @@ export class SchwabConverter extends AbstractConverter {

this.progress.stop()

callback(result);
successCallback(result);
});

// Catch any error.
Expand Down
Loading

0 comments on commit 36a115c

Please sign in to comment.