Major refactoring using ESLint with rules from AirBnb and Vue. Enable most of the ESLint rules and do necessary linting in the code. Also add more information for rules that are disabled to describe what they are and why they are disabled. Allow logging (`console.log`) in test files, and in development mode (e.g. when working with `npm run serve`), but disable it when environment is production (as pre-configured by Vue). Also add flag (`--mode production`) in `lint:eslint` command so production linting is executed earlier in lifecycle. Disable rules that requires a separate work. Such as ESLint rules that are broken in TypeScript: no-useless-constructor (eslint/eslint#14118) and no-shadow (eslint/eslint#13014).
247 lines
9.3 KiB
TypeScript
247 lines
9.3 KiB
TypeScript
import 'mocha';
|
|
import { expect } from 'chai';
|
|
import { UserScriptGenerator } from '@/application/Context/State/Code/Generation/UserScriptGenerator';
|
|
import { SelectedScript } from '@/application/Context/State/Selection/SelectedScript';
|
|
import { ICodeBuilderFactory } from '@/application/Context/State/Code/Generation/ICodeBuilderFactory';
|
|
import { ICodeBuilder } from '@/application/Context/State/Code/Generation/ICodeBuilder';
|
|
import { ScriptStub } from '@tests/unit/stubs/ScriptStub';
|
|
import { ScriptingDefinitionStub } from '@tests/unit/stubs/ScriptingDefinitionStub';
|
|
|
|
describe('UserScriptGenerator', () => {
|
|
describe('scriptingDefinition', () => {
|
|
describe('startCode', () => {
|
|
it('is prepended if not empty', () => {
|
|
// arrange
|
|
const sut = new UserScriptGenerator();
|
|
const startCode = 'Start\nCode';
|
|
const script = new ScriptStub('id')
|
|
.withCode('code\nmulti-lined')
|
|
.toSelectedScript();
|
|
const definition = new ScriptingDefinitionStub()
|
|
.withStartCode(startCode)
|
|
.withEndCode(undefined);
|
|
const expectedStart = `${startCode}\n`;
|
|
// act
|
|
const code = sut.buildCode([script], definition);
|
|
// assert
|
|
const actual = code.code;
|
|
expect(actual.startsWith(expectedStart));
|
|
});
|
|
it('is not prepended if empty', () => {
|
|
// arrange
|
|
const codeBuilderStub = new CodeBuilderStub();
|
|
const sut = new UserScriptGenerator(mockCodeBuilderFactory(codeBuilderStub));
|
|
const script = new ScriptStub('id')
|
|
.withCode('code\nmulti-lined')
|
|
.toSelectedScript();
|
|
const definition = new ScriptingDefinitionStub()
|
|
.withStartCode(undefined)
|
|
.withEndCode(undefined);
|
|
const expectedStart = codeBuilderStub
|
|
.appendFunction(script.script.name, script.script.code.execute)
|
|
.toString();
|
|
// act
|
|
const code = sut.buildCode([script], definition);
|
|
// assert
|
|
const actual = code.code;
|
|
expect(actual.startsWith(expectedStart));
|
|
});
|
|
});
|
|
describe('endCode', () => {
|
|
it('is appended if not empty', () => {
|
|
// arrange
|
|
const sut = new UserScriptGenerator();
|
|
const endCode = 'End\nCode';
|
|
const script = new ScriptStub('id')
|
|
.withCode('code\nmulti-lined')
|
|
.toSelectedScript();
|
|
const definition = new ScriptingDefinitionStub()
|
|
.withEndCode(endCode);
|
|
const expectedEnd = `${endCode}\n`;
|
|
// act
|
|
const code = sut.buildCode([script], definition);
|
|
// assert
|
|
const actual = code.code;
|
|
expect(actual.endsWith(expectedEnd));
|
|
});
|
|
it('is not appended if empty', () => {
|
|
// arrange
|
|
const codeBuilderStub = new CodeBuilderStub();
|
|
const sut = new UserScriptGenerator(mockCodeBuilderFactory(codeBuilderStub));
|
|
const script = new ScriptStub('id')
|
|
.withCode('code\nmulti-lined')
|
|
.toSelectedScript();
|
|
const expectedEnd = codeBuilderStub
|
|
.appendFunction(script.script.name, script.script.code.execute)
|
|
.toString();
|
|
const definition = new ScriptingDefinitionStub()
|
|
.withEndCode(undefined);
|
|
// act
|
|
const code = sut.buildCode([script], definition);
|
|
// assert
|
|
const actual = code.code;
|
|
expect(actual.endsWith(expectedEnd));
|
|
});
|
|
});
|
|
});
|
|
it('appends revert script', () => {
|
|
// arrange
|
|
const sut = new UserScriptGenerator();
|
|
const scriptName = 'test non-revert script';
|
|
const scriptCode = 'REM nop';
|
|
const script = new ScriptStub('id')
|
|
.withName(scriptName)
|
|
.withRevertCode(scriptCode)
|
|
.toSelectedScript(true);
|
|
const definition = new ScriptingDefinitionStub();
|
|
// act
|
|
const actual = sut.buildCode([script], definition);
|
|
// assert
|
|
expect(actual.code).to.include(`${scriptName} (revert)`);
|
|
expect(actual.code).to.include(scriptCode);
|
|
});
|
|
it('appends non-revert script', () => {
|
|
const sut = new UserScriptGenerator();
|
|
// arrange
|
|
const scriptName = 'test non-revert script';
|
|
const scriptCode = 'REM nop';
|
|
const script = new ScriptStub('id').withName(scriptName).withCode(scriptCode);
|
|
const selectedScripts = [new SelectedScript(script, false)];
|
|
const definition = new ScriptingDefinitionStub();
|
|
// act
|
|
const actual = sut.buildCode(selectedScripts, definition);
|
|
// assert
|
|
expect(actual.code).to.include(scriptName);
|
|
expect(actual.code).to.not.include(`${scriptName} (revert)`);
|
|
expect(actual.code).to.include(scriptCode);
|
|
});
|
|
describe('scriptPositions', () => {
|
|
it('without script; returns empty', () => {
|
|
// arrange
|
|
const sut = new UserScriptGenerator();
|
|
const selectedScripts = [];
|
|
const definition = new ScriptingDefinitionStub();
|
|
// act
|
|
const actual = sut.buildCode(selectedScripts, definition);
|
|
// assert
|
|
expect(actual.scriptPositions.size).to.equal(0);
|
|
});
|
|
describe('with scripts', () => {
|
|
// arrange
|
|
const totalStartCodeLines = 2;
|
|
const totalFunctionNameLines = 4;
|
|
const definition = new ScriptingDefinitionStub()
|
|
.withStartCode('First line\nSecond line');
|
|
describe('single script', () => {
|
|
const testCases = [
|
|
{
|
|
name: 'single-lined',
|
|
scriptCode: 'only line',
|
|
codeLines: 1,
|
|
},
|
|
{
|
|
name: 'multi-lined',
|
|
scriptCode: 'first line\nsecond line',
|
|
codeLines: 2,
|
|
},
|
|
];
|
|
const sut = new UserScriptGenerator();
|
|
for (const testCase of testCases) {
|
|
it(testCase.name, () => {
|
|
const expectedStartLine = totalStartCodeLines
|
|
+ 1 // empty line code begin
|
|
+ 1; // code begin
|
|
const expectedEndLine = expectedStartLine
|
|
+ totalFunctionNameLines
|
|
+ testCase.codeLines;
|
|
const selectedScript = new ScriptStub('script-id')
|
|
.withName('script')
|
|
.withCode(testCase.scriptCode)
|
|
.toSelectedScript(false);
|
|
// act
|
|
const actual = sut.buildCode([selectedScript], definition);
|
|
// expect
|
|
expect(1).to.equal(actual.scriptPositions.size);
|
|
const position = actual.scriptPositions.get(selectedScript);
|
|
expect(expectedStartLine).to.equal(position.startLine, 'Unexpected start line position');
|
|
expect(expectedEndLine).to.equal(position.endLine, 'Unexpected end line position');
|
|
});
|
|
}
|
|
});
|
|
it('multiple scripts', () => {
|
|
const sut = new UserScriptGenerator();
|
|
const selectedScripts = [
|
|
new ScriptStub('1').withCode('only line'),
|
|
new ScriptStub('2').withCode('first line\nsecond line'),
|
|
].map((s) => s.toSelectedScript());
|
|
const expectedFirstScriptStart = totalStartCodeLines
|
|
+ 1 // empty line code begin
|
|
+ 1; // code begin
|
|
const expectedFirstScriptEnd = expectedFirstScriptStart
|
|
+ totalFunctionNameLines
|
|
+ 1; // total code lines
|
|
const expectedSecondScriptStart = expectedFirstScriptEnd
|
|
+ 1 // code end hyphens
|
|
+ 1 // new line
|
|
+ 1; // code begin
|
|
const expectedSecondScriptEnd = expectedSecondScriptStart
|
|
+ totalFunctionNameLines
|
|
+ 2; // total lines of second script
|
|
// act
|
|
const actual = sut.buildCode(selectedScripts, definition);
|
|
// assert
|
|
const firstPosition = actual.scriptPositions.get(selectedScripts[0]);
|
|
const secondPosition = actual.scriptPositions.get(selectedScripts[1]);
|
|
expect(actual.scriptPositions.size).to.equal(2);
|
|
expect(expectedFirstScriptStart).to.equal(firstPosition.startLine, 'Unexpected start line position (first script)');
|
|
expect(expectedFirstScriptEnd).to.equal(firstPosition.endLine, 'Unexpected end line position (first script)');
|
|
expect(expectedSecondScriptStart).to.equal(secondPosition.startLine, 'Unexpected start line position (second script)');
|
|
expect(expectedSecondScriptEnd).to.equal(secondPosition.endLine, 'Unexpected end line position (second script)');
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
function mockCodeBuilderFactory(mock: ICodeBuilder): ICodeBuilderFactory {
|
|
return {
|
|
create: () => mock,
|
|
};
|
|
}
|
|
|
|
class CodeBuilderStub implements ICodeBuilder {
|
|
public currentLine = 0;
|
|
|
|
private text = '';
|
|
|
|
public appendLine(code?: string): ICodeBuilder {
|
|
this.text += this.text ? `${code}\n` : code;
|
|
this.currentLine++;
|
|
return this;
|
|
}
|
|
|
|
public appendTrailingHyphensCommentLine(totalRepeatHyphens: number): ICodeBuilder {
|
|
return this.appendLine(`trailing-hyphens-${totalRepeatHyphens}`);
|
|
}
|
|
|
|
public appendCommentLine(commentLine?: string): ICodeBuilder {
|
|
return this.appendLine(`Comment | ${commentLine}`);
|
|
}
|
|
|
|
public appendCommentLineWithHyphensAround(
|
|
sectionName: string,
|
|
totalRepeatHyphens: number,
|
|
): ICodeBuilder {
|
|
return this.appendLine(`hyphens-around-${totalRepeatHyphens} | Section name: ${sectionName} | hyphens-around-${totalRepeatHyphens}`);
|
|
}
|
|
|
|
public appendFunction(name: string, code: string): ICodeBuilder {
|
|
return this
|
|
.appendLine(`Function | Name: ${name}`)
|
|
.appendLine(`Function | Code: ${code}`);
|
|
}
|
|
|
|
public toString(): string {
|
|
return this.text;
|
|
}
|
|
}
|