Skip to content

Commit

Permalink
refactor(ccdaservice): improve DataStack class (openemr#6718)
Browse files Browse the repository at this point in the history
* chore(deps): add jest as dev dependency

* chore(deps): update package-lock.json

* feat(ccdaservice): encapsulate DataStack

* test(ccdaservice): create tests for DataStack class

* refactor(ccdaservice): import and use DataStack from class file

* chore(deps): pin jest version

* refactor(ci): improve lint:js-fix script

* chore(eslint): support for jest

* chore(ci): create step for JS unit tests

* chore(deps): pin package versions
  • Loading branch information
raskolnikov-rodion committed Aug 9, 2023
1 parent 54ed6be commit 787c3da
Show file tree
Hide file tree
Showing 9 changed files with 8,391 additions and 4,997 deletions.
12 changes: 10 additions & 2 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"browser": true,
"commonjs": true,
"es6": true,
"jquery": true
"jquery": true,
"jest/globals": true
},
"extends": ["eslint:recommended"],
"globals": {
Expand All @@ -20,5 +21,12 @@
"no-redeclare": "warn",
"no-useless-escape": "warn",
"no-mixed-spaces-and-tabs": "warn"
}
},
"overrides": [
{
"files": "**/*.spec.js",
"plugins": ["jest"],
"extends": ["plugin:jest/recommended"]
}
]
}
39 changes: 39 additions & 0 deletions .github/workflows/js-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: JS Unit Test

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

permissions:
contents: read

jobs:

js_unit_test:
runs-on: ubuntu-22.04
name: JS Unit Test
steps:
- uses: actions/checkout@v3

- name: Install npm package
uses: actions/setup-node@v3
with:
node-version: '18'

- name: npm install
run: |
failTest=false
npm install || failTest=true
if $failTest; then
exit 1
fi
- name: Run Unit Tests
run: |
failTest=false
npm run test:js || failTest=true
if $failTest; then
exit 1
fi
45 changes: 45 additions & 0 deletions ccdaservice/data-stack/data-stack.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
'use strict';

class DataStack {
#buffer;
#delimiter;

constructor(delimiter) {
this.#delimiter = delimiter;
this.#buffer = '';
}

endOfCcda() {
return this.#buffer.length === 0 || this.#buffer.indexOf(this.#delimiter) === -1;
}

push(data) {
this.#buffer += data;
}

#fetchBuffer() {
const delimiterIndex = this.#buffer.indexOf(this.#delimiter);
if (delimiterIndex === -1) return null;
const data = this.#buffer.slice(0, delimiterIndex);
this.#buffer = this.#buffer.replace(data + this.#delimiter, '');
return data;
}

returnData() {
return this.#fetchBuffer();
}

clear() {
this.#buffer = '';
}

readStackByDelimiter(delimiter) {
const originalDelimiter = this.#delimiter;
this.#delimiter = delimiter;
const message = this.#fetchBuffer();
this.#delimiter = originalDelimiter;
return message;
}
}

exports.DataStack = DataStack;
60 changes: 60 additions & 0 deletions ccdaservice/data-stack/data-stack.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
const DataStack = require('./data-stack.js').DataStack;

describe('DataStack', () => {
const delimiter = ';'
let stack;

beforeEach(() => {
stack = new DataStack(delimiter);
});

it('should create a new stack', () => {
expect(stack).toBeTruthy();
});

it('should store and return data', () => {
const hello = 'Hello';
const world = 'World!';
stack.push(hello + delimiter);
stack.push(world + delimiter);
expect(stack.returnData()).toEqual(hello);
expect(stack.returnData()).toEqual(world);
});

describe('endOfCcda', () => {
it('should return true if there is no data in the stack', () => {
expect(stack.endOfCcda()).toEqual(true);
});

it('should return true if the delimiter is not part of the data', () => {
stack.push('Undelimited data');
expect(stack.endOfCcda()).toEqual(true);
});

it('should return false otherwise', () => {
stack.push(`OpenEMR${delimiter}`);
expect(stack.endOfCcda()).toEqual(false);
});
});

describe('clear', () => {
it('should remove all data from the stack', () => {
stack.push(`OpenEMR${delimiter}`);
stack.clear();
expect(stack.endOfCcda()).toEqual(true);
});
});

describe('readStackByDelimiter', () => {
beforeEach(() => stack.push(`OpenEMR!The best app${delimiter}`));

it('should be able to read the stack using a different delimiter', () => {
expect(stack.readStackByDelimiter('!')).toEqual('OpenEMR');
});

it('should preserve the original delimiter for future readings', () => {
stack.readStackByDelimiter('!');
expect(stack.returnData()).toEqual('The best app');
});
});
});
20 changes: 12 additions & 8 deletions ccdaservice/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 2 additions & 43 deletions ccdaservice/serveccda.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const server = net.createServer();
const to_json = require('xmljson').to_json;
const bbg = require(__dirname + '/oe-blue-button-generate');
const fs = require('fs');
const DataStack = require('./data-stack/data-stack').DataStack;

var conn = ''; // make our connection scope global to script
var oidFacility = "";
Expand All @@ -26,48 +27,6 @@ var webRoot = "";
var authorDateTime = '';
var documentLocation = '';

class DataStack {
constructor(delimiter) {
this.delimiter = delimiter;
this.buffer = "";
}

endOfCcda() {
return this.buffer.length === 0 || this.buffer.indexOf(this.delimiter) === -1;
}

pushToStack(data) {
this.buffer += data;
}

fetchBuffer() {
const delimiterIndex = this.buffer.indexOf(this.delimiter);
if (delimiterIndex !== -1) {
const bufferMsg = this.buffer.slice(0, delimiterIndex);
this.buffer = this.buffer.replace(bufferMsg + this.delimiter, "");
return bufferMsg;
}
return null
}

returnData() {
return this.fetchBuffer();
}

clearStack() {
this.buffer = "";
}

readStackByDelimiter(delimiter) {
let backup = this.delimiter;
let part = '';
this.delimiter = delimiter;
part = this.fetchBuffer();
this.delimiter = backup;
return part;
}
}

function trim(s) {
if (typeof s === 'string') return s.trim();
return s;
Expand Down Expand Up @@ -3515,7 +3474,7 @@ function processConnection(connection) {
// CCM will send one File Separator characters to mark end of array.
let received = new DataStack(String.fromCharCode(28));
conn.on("data", data => {
received.pushToStack(data);
received.push(data);
while (!received.endOfCcda() && data.length > 0) {
data = "";
eventData(received.returnData());
Expand Down
9 changes: 9 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/** @type {import('jest').Config} */
const config = {
modulePathIgnorePatterns: [
'public/assets',
'vendor'
]
};

module.exports = config;
Loading

0 comments on commit 787c3da

Please sign in to comment.