Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge dev into main #5

Merged
merged 11 commits into from
Nov 30, 2024
44 changes: 6 additions & 38 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,8 @@ on:
branches:
- dev

# permissions:
# actions: read
# contents: read

jobs:
ci-renderer:
ci:
runs-on: ubuntu-latest
steps:
- name: Check out Git repository
Expand All @@ -29,10 +25,15 @@ jobs:
node-version-file: '.nvmrc'
cache: npm

- name: Add missing dependencies on act
if: ${{ env.ACT }}
run: apt-get update && apt-get install xvfb libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libnss3 libxss1 libasound2 libxtst6 xauth xvfb -y

- name: Install dependencies
run: npm ci

- name: Derive appropriate SHAs for base and head for `nx affected` commands
if: ${{ !env.ACT }}
uses: nrwl/nx-set-shas@v4

- name: Run CI on affected projects
Expand All @@ -55,36 +56,3 @@ jobs:
if: ${{ steps.nx-release.outputs.new_release_version != '' }}
run: |
echo "Version ${{ steps.nx-release.outputs.new_release_version }} will be released" >> $GITHUB_STEP_SUMMARY

ci-electron:
needs: [ci-renderer]
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]

steps:
- name: Check out Git repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup NodeJS
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: npm

- name: Install setuptools on macOS
if: matrix.os == 'macos-latest'
run: python3 -m pip install setuptools --break-system-packages

- name: Install dependencies
run: npm ci

- name: Build
run: npx nx run-many -t build --prod

- name: Build unpacked executable
run: npx nx run spie:package
7 changes: 5 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@
// Eslint settings
"eslint.useFlatConfig": true,

// Code spell checker serrings
// Code spell checker settings
"cSpell.language": "en,en-AU",
"cSpell.words": ["Oliveira", "Scrollback", "SPIE"]
"cSpell.words": ["Oliveira", "Scrollback", "SPIE"],

// Commitlint settings
"commitlint.preferBundledLibraries": true
}
87 changes: 0 additions & 87 deletions apps/spie-ui-e2e/src/e2e/app.cy.ts

This file was deleted.

201 changes: 201 additions & 0 deletions apps/spie-ui-e2e/src/e2e/send.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
import { type SerialPortEvent } from '@spie/types';

import { mockElectronAPI } from '../fixtures/mocks/electron-api.mock';

describe('Send component', () => {
const mockSerialPortList = [
{ path: '/dev/ttyUSB0', manufacturer: 'Manufacturer1' },
{ path: '/dev/ttyUSB1', manufacturer: 'Manufacturer2' },
];

let onEventTrigger: ((event: SerialPortEvent) => void) | null;

beforeEach(() => {
cy.visit('/');

cy.on('window:before:load', (win) => {
const listeners: Array<(serialPortEvent: SerialPortEvent) => void> = [];

win.electron = mockElectronAPI();
win.electron.serialPort.list = cy.stub().resolves(mockSerialPortList);

win.electron.serialPort.onEvent = cy
.stub()
.callsFake((callback: (serialPortEvent: SerialPortEvent) => void) => {
listeners.push(callback);

onEventTrigger = (serialPortEvent) => {
listeners.forEach((listener) => listener(serialPortEvent));
};

return () => {
const index = listeners.indexOf(callback);
if (index !== -1) {
listeners.splice(index, 1);
}
};
});
});
});

it('should enable/disable send based on serial port status', () => {
const data = 'test test test test test test test test test test';

cy.wrap(null).then(() => {
if (onEventTrigger) {
onEventTrigger({ event: 'open' });
}
});

cy.get('app-send ion-input input').invoke('val', data).trigger('input');

cy.get('app-send ion-button')
.contains('Send')
.should('not.have.class', 'button-disabled');

cy.wrap(null).then(() => {
if (onEventTrigger) {
onEventTrigger({ event: 'close' });
}
});

cy.get('app-send ion-button')
.contains('Send')
.should('have.class', 'button-disabled');
});

it('should clear input after pressing clear input button', () => {
const data = 'test test test test test test test test test test';

cy.wrap(null).then(() => {
if (onEventTrigger) {
onEventTrigger({ event: 'open' });
}
});

cy.get('app-send ion-input input').invoke('val', data).trigger('input');
cy.get('app-send ion-input button').click();

cy.get('app-send ion-input input').should('have.value', '');
});

it('should send input with default options', () => {
const data = 'test test test test test test test test test test';
const formattedData = `${data}\n`;

cy.wrap(null).then(() => {
if (onEventTrigger) {
onEventTrigger({ event: 'open' });
}
});

cy.get('app-send ion-input input').invoke('val', data).trigger('input');

cy.get('app-send ion-button').contains('Send').click();

cy.window().then((win) => {
cy.wrap(win.electron.serialPort.write).should(
'have.been.calledOnceWithExactly',
formattedData,
'ascii'
);
});
});

it('should open and close the advanced modal', () => {
cy.get('app-send ion-button ion-icon').parent().click();
cy.get('ion-modal').should('be.visible');
cy.get('ion-modal ion-toolbar ion-button').click();
cy.get('ion-modal').should('not.be.visible');
});

it('should clear input after changing encoding', () => {
const data = 'test test test test test test test test test test';
cy.get('app-send ion-input input').invoke('val', data).trigger('input');

cy.get('app-send ion-button ion-icon').parent().click();
cy.getAdvancedModalSelectElement(
'send-advanced-modal',
'Encoding'
).selectOption('Hex');
cy.get('ion-modal ion-toolbar ion-button').click();

cy.get('app-send ion-input input').should('have.value', '');
});

it('should format hex input', () => {
const data = 'test test test test test test test test test test';
const expectedHexData = 'EE EE EE EE EE';

cy.get('app-send ion-button ion-icon').parent().click();
cy.getAdvancedModalSelectElement(
'send-advanced-modal',
'Encoding'
).selectOption('Hex');
cy.get('ion-modal ion-toolbar ion-button').click();

cy.get('app-send ion-input input').invoke('val', data).trigger('input');

cy.get('app-send ion-input input').should('have.value', expectedHexData);
});

it('should send input with hex encoding', () => {
const data = 'test test test test test test test test test test\n\n\n';
const formattedData = 'EEEEEEEEEE';

cy.get('app-send ion-button ion-icon').parent().click();
cy.getAdvancedModalSelectElement(
'send-advanced-modal',
'Encoding'
).selectOption('Hex');
cy.get('ion-modal ion-toolbar ion-button').click();

cy.wrap(null).then(() => {
if (onEventTrigger) {
onEventTrigger({ event: 'open' });
}
});

cy.get('app-send ion-input input').invoke('val', data).trigger('input');

cy.get('app-send ion-button').contains('Send').click();

cy.window().then((win) => {
cy.wrap(win.electron.serialPort.write).should(
'have.been.calledOnceWithExactly',
formattedData,
'hex'
);
});
});

it('should send input with advanced delimiter', () => {
const data = 'test test test test test test test test test test';
const formattedData = `${data}\r\n`;

cy.get('app-send ion-button ion-icon').parent().click();
cy.getAdvancedModalSelectElement(
'send-advanced-modal',
'Delimiter'
).selectOption('CRLF (\\r\\n)');
cy.get('ion-modal ion-toolbar ion-button').click();

cy.wrap(null).then(() => {
if (onEventTrigger) {
onEventTrigger({ event: 'open' });
}
});

cy.get('app-send ion-input input').invoke('val', data).trigger('input');

cy.get('app-send ion-button').contains('Send').click();

cy.window().then((win) => {
cy.wrap(win.electron.serialPort.write).should(
'have.been.calledOnceWithExactly',
formattedData,
'ascii'
);
});
});
});
Loading