Improve testing, linting, and node usage in devcontainer

* Swtch to devcontainer for node 18.x and remove terminal/launch settings for version (removes nvm dependency in container)
* Update eslint config to use proper config for include/ignore files
* Add spec for mocha and mocha test runner extension + settings
This commit is contained in:
FoxxMD 2024-10-08 19:33:47 +00:00
parent 22d17ba621
commit 6780d72296
7 changed files with 72 additions and 74 deletions

View file

@ -3,19 +3,26 @@
{
"name": "Node.js",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/javascript-node:1-22-bookworm",
"image": "mcr.microsoft.com/devcontainers/javascript-node:1-18-bookworm",
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [9078]
"forwardPorts": [9078],
// Use 'postCreateCommand' to run commands after the container is created.
//"postCreateCommand": "./.devcontainer/postCreateCommand.sh"
// Configure tool-specific properties.
// "customizations": {},
"customizations": {
"vscode": {
"extensions": [
"hbenl.vscode-mocha-test-adapter",
"dbaeumer.vscode-eslint"
]
}
}
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"

View file

@ -1,5 +1,6 @@
{
"reporter": "dot",
"extension": "ts",
"import": "tsx/esm"
"import": "tsx/esm",
"spec": "./src/backend/tests/**/*.test.ts"
}

4
.vscode/launch.json vendored
View file

@ -4,7 +4,6 @@
{
"name": "dev",
"type": "node",
"runtimeVersion": "18.19.1",
"request": "launch",
// Debug current file in VSCode
"program": "${workspaceFolder}/src/backend/index.ts",
@ -20,7 +19,6 @@
{
"name": "tsx",
"type": "node",
"runtimeVersion": "18.19.1",
"request": "launch",
// Debug current file in VSCode
"program": "${file}",
@ -47,7 +45,6 @@
"--recursive",
"${workspaceFolder}/src/backend/tests/**/*.test.ts"
],
"runtimeVersion": "18.19.1",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/tsx",
"internalConsoleOptions": "openOnSessionStart",
"name": "Mocha Tests",
@ -72,7 +69,6 @@
"--config", "${workspaceRoot}/.mocharc.json",
"${file}"
],
"runtimeVersion": "18.19.1",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/tsx",
"internalConsoleOptions": "openOnSessionStart",
"name": "Mocha Test on File",

View file

@ -1,5 +1,5 @@
{
"debug.javascript.terminalOptions": {
"runtimeVersion": "18.19.1"
}
"mochaExplorer.require": "tsx/esm",
"mochaExplorer.timeout": 1200000,
"mochaExplorer.exit": true
}

View file

@ -4,40 +4,33 @@ import eslint from '@eslint/js';
import tsEslint from 'typescript-eslint';
import arrow from 'eslint-plugin-prefer-arrow-functions';
export default tsEslint.config(
eslint.configs.recommended,
...tsEslint.configs.recommended,
// use to enable typed linting (way more errors) https://typescript-eslint.io/linting/typed-linting
/* ...tsEslint.configs.recommendedTypeChecked,
{
languageOptions: {
parserOptions: {
project: true,
tsconfigDirName: import.meta.dirname,
},
},
},*/
{
files: ['src/backend/**/*.ts'],
ignores: ['eslint.config.js'],
plugins: {
"prefer-arrow-functions": arrow
},
rules: {
'no-useless-catch': 'off',
'@typescript-eslint/no-unused-vars': 'off',
"prefer-arrow-functions/prefer-arrow-functions": [
"warn",
{
"allowNamedFunctions": false,
"classPropertiesAllowed": false,
"disallowPrototype": false,
"returnStyle": "unchanged",
"singleReturnOnly": false
}
],
"arrow-body-style": ["warn", "as-needed"],
"@typescript-eslint/no-explicit-any": "warn"
}
export default tsEslint.config({
files: ['src/backend/**/*.ts'],
plugins: {
"prefer-arrow-functions": arrow
},
ignores: [
'eslint.config.js',
'src/backend/tests/**/*.ts'
],
extends: [
eslint.configs.recommended,
...tsEslint.configs.recommended,
],
rules: {
'no-useless-catch': 'off',
'@typescript-eslint/no-unused-vars': 'off',
"prefer-arrow-functions/prefer-arrow-functions": [
"warn",
{
"allowNamedFunctions": false,
"classPropertiesAllowed": false,
"disallowPrototype": false,
"returnStyle": "unchanged",
"singleReturnOnly": false
}
],
"arrow-body-style": ["warn", "as-needed"],
"@typescript-eslint/no-explicit-any": "warn"
}
);
});

View file

@ -12,7 +12,7 @@
"schema-aioclient": "typescript-json-schema src/backend/tsconfig.json AIOClientConfig --out src/backend/common/schema/aio-client.json --titles --required --tsNodeRegister --refs --validationKeywords deprecationMessage --constAsEnum",
"circular": "madge --circular --extensions ts src/index.ts",
"test": "npm run -s test:backend",
"test:backend": "mocha --reporter spec --recursive src/backend/tests/**/*.test.ts",
"test:backend": "mocha --reporter spec",
"dev": "nodemon -w src/backend -x tsx src/backend/index.ts",
"start": "NODE_ENV=production tsx src/backend/index.ts",
"build:frontend": "vite build",

View file

@ -23,6 +23,7 @@ describe('Play Transforms', function () {
beforeEach(function() {
component.config = {};
// @ts-expect-error should be built on every test
component.transformRules = undefined;
});
@ -89,10 +90,10 @@ describe('Play Transforms', function () {
component.buildTransformRules();
expect(component.transformRules.preCompare[0]).to.exist;
expect(component.transformRules.preCompare[0].title).to.exist;
expect(Array.isArray(component.transformRules.preCompare[0].title)).is.true;
expect( isConditionalSearchAndReplace(component.transformRules.preCompare[0].title[0])).is.true
expect(component.transformRules.preCompare![0]).to.exist;
expect(component.transformRules.preCompare![0].title).to.exist;
expect(Array.isArray(component.transformRules.preCompare![0].title)).is.true;
expect( isConditionalSearchAndReplace(component.transformRules.preCompare![0].title![0])).is.true
});
it('Converts transform config into real S&P data with default being empty string', function() {
@ -108,12 +109,12 @@ describe('Play Transforms', function () {
component.buildTransformRules();
expect(component.transformRules.preCompare[0]).to.exist;
expect(component.transformRules.preCompare[0].title).to.exist;
expect(Array.isArray(component.transformRules.preCompare[0].title)).is.true;
expect( isConditionalSearchAndReplace(component.transformRules.preCompare[0].title[0])).is.true
expect( component.transformRules.preCompare[0].title[0].search).is.eq('something');
expect( component.transformRules.preCompare[0].title[0].replace).is.eq('');
expect(component.transformRules.preCompare![0]).to.exist;
expect(component.transformRules.preCompare![0].title).to.exist;
expect(Array.isArray(component.transformRules.preCompare![0].title)).is.true;
expect( isConditionalSearchAndReplace(component.transformRules.preCompare![0].title![0])).is.true
expect( component.transformRules.preCompare![0].title![0].search).is.eq('something');
expect( component.transformRules.preCompare![0].title![0].replace).is.eq('');
});
it('Respects transform config when it is already S&P data', function() {
@ -134,12 +135,12 @@ describe('Play Transforms', function () {
component.buildTransformRules();
expect(component.transformRules.preCompare[0]).to.exist;
expect(component.transformRules.preCompare[0].title).to.exist;
expect(Array.isArray(component.transformRules.preCompare[0].title)).is.true;
expect( isConditionalSearchAndReplace(component.transformRules.preCompare[0].title[0])).is.true
expect( component.transformRules.preCompare[0].title[0].search).is.eq('nothing');
expect( component.transformRules.preCompare[0].title[0].replace).is.eq('anything');
expect(component.transformRules.preCompare![0]).to.exist;
expect(component.transformRules.preCompare![0].title).to.exist;
expect(Array.isArray(component.transformRules.preCompare![0].title)).is.true;
expect( isConditionalSearchAndReplace(component.transformRules.preCompare![0].title![0])).is.true
expect( component.transformRules.preCompare![0].title![0].search).is.eq('nothing');
expect( component.transformRules.preCompare![0].title![0].replace).is.eq('anything');
});
});
@ -257,8 +258,8 @@ describe('Play Transforms', function () {
const play = generatePlay({artists: ['something', 'big']});
const transformed = component.transformPlay(play, TRANSFORM_HOOK.preCompare);
expect(transformed.data.artists.length).is.eq(1)
expect(transformed.data.artists[0]).is.eq('big')
expect(transformed.data.artists!.length).is.eq(1)
expect(transformed.data.artists![0]).is.eq('big')
});
});
@ -284,8 +285,8 @@ describe('Play Transforms', function () {
const play = generatePlay({artists: ['something', 'big'], album: 'It Has No Match'});
const transformed = component.transformPlay(play, TRANSFORM_HOOK.preCompare);
expect(transformed.data.artists.length).is.eq(2)
expect(transformed.data.artists[0]).is.eq('something')
expect(transformed.data.artists!.length).is.eq(2)
expect(transformed.data.artists![0]).is.eq('something')
});
it('Does run hook if when conditions matches', function () {
@ -307,8 +308,8 @@ describe('Play Transforms', function () {
const play = generatePlay({artists: ['something', 'big'], album: 'It Has This Match'});
const transformed = component.transformPlay(play, TRANSFORM_HOOK.preCompare);
expect(transformed.data.artists.length).is.eq(1)
expect(transformed.data.artists[0]).is.eq('big')
expect(transformed.data.artists!.length).is.eq(1)
expect(transformed.data.artists![0]).is.eq('big')
});
});
@ -337,8 +338,8 @@ describe('Play Transforms', function () {
const play = generatePlay({artists: ['something', 'big'], album: 'It Has No Match'});
const transformed = component.transformPlay(play, TRANSFORM_HOOK.preCompare);
expect(transformed.data.artists.length).is.eq(2)
expect(transformed.data.artists[0]).is.eq('something')
expect(transformed.data.artists!.length).is.eq(2)
expect(transformed.data.artists![0]).is.eq('something')
});
it('Does run hook if when conditions matches', function () {
@ -365,8 +366,8 @@ describe('Play Transforms', function () {
const play = generatePlay({artists: ['something', 'big'], album: 'It Has This Match'});
const transformed = component.transformPlay(play, TRANSFORM_HOOK.preCompare);
expect(transformed.data.artists.length).is.eq(1)
expect(transformed.data.artists[0]).is.eq('big')
expect(transformed.data.artists!.length).is.eq(1)
expect(transformed.data.artists![0]).is.eq('big')
});
});