Skip to content

Commit

Permalink
Merge pull request #8 from hemit-s/jat-61
Browse files Browse the repository at this point in the history
JAT-61 Cucumber Testing
  • Loading branch information
xenown authored Jun 21, 2022
2 parents e71f67d + c6829b0 commit 8380240
Show file tree
Hide file tree
Showing 18 changed files with 27,327 additions and 16,611 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ jobs:
npm run package
npm run lint
npm exec tsc
npm test
npm run test:unit
43,511 changes: 26,983 additions & 16,528 deletions package-lock.json

Large diffs are not rendered by default.

19 changes: 16 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@
"start:main": "cross-env NODE_ENV=development electronmon -r ts-node/register/transpile-only .",
"start:preload": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.preload.dev.ts",
"start:renderer": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack serve --config ./.erb/configs/webpack.config.renderer.dev.ts",
"test": "jest"
"test": "jest",
"test:unit": "jest --testMatch **/__tests__/unit_tests/*.ts?(x)",
"test:cucumber": "jest --testMatch **/__tests__/cucumber_tests/*.ts?(x)"
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
Expand Down Expand Up @@ -94,7 +96,14 @@
],
"transform": {
"\\.(ts|tsx|js|jsx)$": "ts-jest"
}
},
"testMatch": [
"**/__tests__/*_tests/*.ts?(x)"
],
"transformIgnorePatterns": [
"/node_modules/(?!(uuid)/)",
"\\.pnp\\.[^\\/]+$"
]
},
"dependencies": {
"electron-debug": "^3.2.0",
Expand Down Expand Up @@ -129,6 +138,7 @@
"detect-port": "^1.3.0",
"electron": "^18.2.3",
"electron-builder": "^23.0.3",
"electron-chromedriver": "^18.0.0",
"electron-devtools-installer": "^3.2.0",
"electron-notarize": "^1.2.1",
"electron-rebuild": "^3.2.7",
Expand All @@ -146,10 +156,12 @@
"eslint-plugin-react": "^7.29.4",
"eslint-plugin-react-hooks": "^4.5.0",
"file-loader": "^6.2.0",
"get-random-values-polypony": "^1.0.0",
"html-webpack-plugin": "^5.5.0",
"husky": "^8.0.1",
"identity-obj-proxy": "^3.0.0",
"jest": "^28.1.0",
"jest-cucumber": "^3.0.1",
"jest-environment-jsdom": "^28.1.0",
"lint-staged": "^12.4.1",
"mini-css-extract-plugin": "^2.6.0",
Expand All @@ -167,6 +179,7 @@
"ts-node": "^10.7.0",
"typescript": "^4.6.4",
"url-loader": "^4.1.1",
"webdriverio": "^7.20.2",
"webpack": "^5.72.1",
"webpack-bundle-analyzer": "^4.5.0",
"webpack-cli": "^4.9.2",
Expand Down Expand Up @@ -258,4 +271,4 @@
],
"logLevel": "quiet"
}
}
}
4 changes: 2 additions & 2 deletions release/app/package-lock.json

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

2 changes: 1 addition & 1 deletion release/app/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "aqua",
"version": "0.0.2",
"version": "0.0.3",
"description": "An audio equalizer app",
"license": "MIT",
"author": {
Expand Down
10 changes: 10 additions & 0 deletions src/__tests__/cucumber_tests/features/set_band_gain.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Feature: Set gain of a frequency band
Users want to change the gain of a filter applied to a certain frequency

Scenario: Move slider to bottom
Given Peace is installed
And Peace is running
And Aqua is not running
When Aqua is launched
And I set gain of slider of frequency 100Hz to bottom
Then Peace should show gain of -30dB for frequency 100Hz
44 changes: 44 additions & 0 deletions src/__tests__/cucumber_tests/set_band_gain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { loadFeature, defineFeature } from 'jest-cucumber';
import getRandomValuesPolyPony from 'get-random-values-polypony'; // Need this to fix jest-cucumber's reliance on uuid's getRandomValues
import {
Driver,
startChromeDriver,
stopChromeDriver,
} from '__tests__/utils/webdriver';
import { givenAquaIsNotRunning, whenAquaIsLaunched } from './shared_steps/aqua';
import { whenSetFrequencyGain } from './shared_steps/aquaSlider';
import {
givenPeaceIsRunning,
givenPeaceIsInstalled,
thenPeaceFrequencyGain,
} from './shared_steps/peace';

// shim the getRandomValues function used in uuid which is used by jest-cucumber
// so that it works in electron environment.
getRandomValuesPolyPony.polyfill();
const chromeDriver = startChromeDriver();

const feature = loadFeature(
'./src/__tests__/cucumber_tests/features/set_band_gain.feature'
);
const webdriver: { driver: Driver } = { driver: undefined };

defineFeature(feature, (test) => {
test('Move slider to bottom', async ({ given, when, then }) => {
givenPeaceIsInstalled(given);
givenPeaceIsRunning(given);
givenAquaIsNotRunning(given);

whenAquaIsLaunched(when, webdriver, chromeDriver);
whenSetFrequencyGain(when, webdriver);

thenPeaceFrequencyGain(then, webdriver);
}, 30000);
});

afterAll(() => {
if (webdriver.driver) {
webdriver.driver.deleteSession();
}
stopChromeDriver(chromeDriver);
});
21 changes: 21 additions & 0 deletions src/__tests__/cucumber_tests/shared_steps/aqua.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ChildProcessWithoutNullStreams } from 'child_process';
import { DefineStepFunction } from 'jest-cucumber';
import getWebDriver, { Driver } from '__tests__/utils/webdriver';

export const givenAquaIsNotRunning = (given: DefineStepFunction) => {
given('Aqua is not running', () => {
// TODO find out how to check if aqua is not running. find a way to close aqua
});
};

export const whenAquaIsLaunched = (
when: DefineStepFunction,
webdriver: { driver: Driver | undefined },
chromeDriverProcess: ChildProcessWithoutNullStreams
) => {
when('Aqua is launched', async () => {
webdriver.driver = await getWebDriver(chromeDriverProcess);
// Wait 10 seconds for the app to launch and load screen
await new Promise((resolve) => setTimeout(resolve, 10000));
});
};
40 changes: 40 additions & 0 deletions src/__tests__/cucumber_tests/shared_steps/aquaSlider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { DefineStepFunction } from 'jest-cucumber';
import { Driver } from '__tests__/utils/webdriver';

export const whenSetFrequencyGain = (
when: DefineStepFunction,
webdriver: { driver: Driver | undefined }
) => {
when(
/^I set gain of slider of frequency (\d+)Hz to (top|middle|bottom)$/,
async (frequency: number, position: string) => {
const sliderElem = await webdriver.driver.$(
`[name="${frequency}-range"]`
);
const coord = { x: 0, y: 0 };
if (position === 'top') {
coord.y = -100;
} else if (position === 'bottom') {
coord.y = 100;
}
sliderElem.dragAndDrop(coord);
// wait 1000 ms for the action.
await new Promise((resolve) => setTimeout(resolve, 1000));
}
);
};

export const givenSetFrequencyGain = (
given: DefineStepFunction,
webdriver: { driver: Driver | undefined }
) => {
given(
/^I set gain of slider of frequency (\d+)Hz to (top|middle|bottom)$/,
async (frequency: number, position: string) => {
console.log(`frequency: ${frequency}`);
console.log(`position: ${position}`);
// TODO use webdriver io get slider position
console.log(webdriver.driver);
}
);
};
65 changes: 65 additions & 0 deletions src/__tests__/cucumber_tests/shared_steps/peace.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { peaceGainOutputToDb } from 'common/peaceConversions';
import {
getPeaceWindowHandle,
isPeaceRunning,
sendPeaceCommand,
} from 'common/peaceIPC';
import { DefineStepFunction } from 'jest-cucumber';
import { Driver } from '__tests__/utils/webdriver';
import registry from '../../../main/registry';

export const givenPeaceIsInstalled = (given: DefineStepFunction) => {
given('Peace is installed', async () => {
if (!(await registry.isPeaceInstalled())) {
throw new Error('Peace not installed');
}
// TODO find a way to install peace
});
};

export const givenPeaceIsRunning = (given: DefineStepFunction) => {
given('Peace is running', async () => {
// Need retries as this check can be flakey.
for (let i = 0; i < 3; i += 1) {
const peaceHWnd = getPeaceWindowHandle();
const foundPeace = isPeaceRunning(peaceHWnd);
if (foundPeace) {
return;
}
// Wait 1s before trying again
// eslint-disable-next-line no-await-in-loop
await new Promise((resolve) => setTimeout(resolve, 1000));
}
throw new Error('Peace not running');
// For now, we need to manually start peace before running end-to-end tests
});
};

export const thenPeaceFrequencyGain = (
then: DefineStepFunction,
webdriver: { driver: Driver | undefined }
) => {
then(
/^Peace should show gain of (-?\d+)dB for frequency (\d+)Hz$/,
async (gain: string, frequency: string) => {
const sliderElems = await webdriver.driver
.$('.mainContent')
.$$('div*=Hz');
for (let i = 0; i < sliderElems.length; i += 1) {
// eslint-disable-next-line no-await-in-loop
const text = await sliderElems[i].getText();
if (text === `${frequency} Hz`) {
// eslint-disable-next-line no-await-in-loop
const peaceHWnd = getPeaceWindowHandle();
if (!isPeaceRunning(peaceHWnd)) {
throw new Error('Peace is not running.');
}
const peaceGain = sendPeaceCommand(peaceHWnd, 100 + i + 1, 5, 0);
expect(peaceGainOutputToDb(peaceGain)).toBe(parseInt(gain, 10));
return;
}
}
throw new Error(`${frequency} Hz gain band not found.`);
}
);
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import '@testing-library/jest-dom';
import { render } from '@testing-library/react';
import App from '../renderer/App';
import App from '../../renderer/App';

describe('App', () => {
it('should render', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import '@testing-library/jest-dom';
import { fireEvent, render, screen } from '@testing-library/react';
import Switch from '../renderer/Switch';
import Switch from '../../renderer/Switch';

describe('Switch', () => {
const id = 'switch';
Expand Down
46 changes: 46 additions & 0 deletions src/__tests__/utils/webdriver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { remote, RemoteOptions } from 'webdriverio';
import path from 'path';

import { ChildProcessWithoutNullStreams, spawn } from 'child_process';

const options: RemoteOptions = {
hostname: 'localhost', // Use localhost as chrome driver server
port: 9515, // "9515" is the port opened by chrome driver.
capabilities: {
browserName: 'chrome',
'goog:chromeOptions': {
binary: path.join(
process.env.USERPROFILE ? process.env.USERPROFILE : '',
'AppData/Local/Programs/aqua/AQUA.exe'
),
args: [],
},
},
};

export const startChromeDriver = () => {
return spawn('chromedriver.exe', ['--port=9515'], {
shell: true,
cwd: path.join(
__dirname,
'../../../node_modules/electron-chromedriver/bin'
),
});
};

export const stopChromeDriver = (
chromeDriverProcess: ChildProcessWithoutNullStreams
) => {
return chromeDriverProcess.kill(9);
};

export default async function getWebDriver(
chromeDriverProcess: ChildProcessWithoutNullStreams
) {
if (chromeDriverProcess === undefined) {
throw new Error('chrome driver not started.');
}
return remote(options);
}

export type Driver = Awaited<ReturnType<typeof getWebDriver>>;
36 changes: 36 additions & 0 deletions src/common/peaceConversions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Peace returns numerical values as unsigned integers
// This is the offset for the value -1000, used when fetching gain values
const OVERFLOW_OFFSET = 4294967296;

export const peaceGainOutputToDb = (result: number) => {
const MAX_GAIN = 30;
const MIN_GAIN = -30;

// If gain is larger than MAX_GAIN, assume that Peace returned an unsigned negative number
// If after adjusting for the unsigned number gives a positive value, default to -30
if (result / 1000 > MAX_GAIN && (result - OVERFLOW_OFFSET) / 1000 > 0) {
return MIN_GAIN;
}

const gain =
result / 1000 > MAX_GAIN
? (result - OVERFLOW_OFFSET) / 1000 // Unsigned negative case
: result / 1000; // Positive value case

// Round up any lower gain values up to MIN_GAIN
return Math.max(gain, MIN_GAIN);
};

export const peaceFrequencyOutputToNormal = (result: number) => {
const MAX_FREQUENCY = 22050;
const MIN_FREQUENCY = 10;

// If gain is larger than the MAX_FREQUENCY, assume that Peace returned an unsigned negative number
// Since frequency shouldn't be negative, default to the MIN_FREQUENCY
if (result > MAX_FREQUENCY) {
return MIN_FREQUENCY;
}

// Round up any lower frequency values up to MIN_FREQUENCY
return Math.max(result, MIN_FREQUENCY);
};
Loading

0 comments on commit 8380240

Please sign in to comment.