Refactor to enforce strictNullChecks
This commit applies `strictNullChecks` to the entire codebase to improve maintainability and type safety. Key changes include: - Remove some explicit null-checks where unnecessary. - Add necessary null-checks. - Refactor static factory functions for a more functional approach. - Improve some test names and contexts for better debugging. - Add unit tests for any additional logic introduced. - Refactor `createPositionFromRegexFullMatch` to its own function as the logic is reused. - Prefer `find` prefix on functions that may return `undefined` and `get` prefix for those that always return a value.
This commit is contained in:
@@ -9,25 +9,13 @@ import { ExpressionEvaluationContextStub } from '@tests/unit/shared/Stubs/Expres
|
||||
import { IPipelineCompiler } from '@/application/Parser/Script/Compiler/Expressions/Pipes/IPipelineCompiler';
|
||||
import { PipelineCompilerStub } from '@tests/unit/shared/Stubs/PipelineCompilerStub';
|
||||
import { IReadOnlyFunctionParameterCollection } from '@/application/Parser/Script/Compiler/Function/Parameter/IFunctionParameterCollection';
|
||||
import { getAbsentObjectTestCases, itEachAbsentObjectValue } from '@tests/unit/shared/TestCases/AbsentTests';
|
||||
import { itEachAbsentObjectValue } from '@tests/unit/shared/TestCases/AbsentTests';
|
||||
import { IExpressionEvaluationContext } from '@/application/Parser/Script/Compiler/Expressions/Expression/ExpressionEvaluationContext';
|
||||
import { expectExists } from '@tests/shared/Assertions/ExpectExists';
|
||||
|
||||
describe('Expression', () => {
|
||||
describe('ctor', () => {
|
||||
describe('position', () => {
|
||||
describe('throws when missing', () => {
|
||||
itEachAbsentObjectValue((absentValue) => {
|
||||
// arrange
|
||||
const expectedError = 'missing position';
|
||||
const position = absentValue;
|
||||
// act
|
||||
const act = () => new ExpressionBuilder()
|
||||
.withPosition(position)
|
||||
.build();
|
||||
// assert
|
||||
expect(act).to.throw(expectedError);
|
||||
});
|
||||
});
|
||||
it('sets as expected', () => {
|
||||
// arrange
|
||||
const expected = new ExpressionPosition(0, 5);
|
||||
@@ -52,7 +40,7 @@ describe('Expression', () => {
|
||||
expect(actual.parameters);
|
||||
expect(actual.parameters.all);
|
||||
expect(actual.parameters.all.length).to.equal(0);
|
||||
});
|
||||
}, { excludeNull: true });
|
||||
});
|
||||
it('sets as expected', () => {
|
||||
// arrange
|
||||
@@ -67,21 +55,6 @@ describe('Expression', () => {
|
||||
expect(actual.parameters).to.deep.equal(expected);
|
||||
});
|
||||
});
|
||||
describe('evaluator', () => {
|
||||
describe('throws if missing', () => {
|
||||
itEachAbsentObjectValue((absentValue) => {
|
||||
// arrange
|
||||
const expectedError = 'missing evaluator';
|
||||
const evaluator = absentValue;
|
||||
// act
|
||||
const act = () => new ExpressionBuilder()
|
||||
.withEvaluator(evaluator)
|
||||
.build();
|
||||
// assert
|
||||
expect(act).to.throw(expectedError);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('evaluate', () => {
|
||||
describe('throws with invalid arguments', () => {
|
||||
@@ -91,11 +64,6 @@ describe('Expression', () => {
|
||||
expectedError: string,
|
||||
sutBuilder?: (builder: ExpressionBuilder) => ExpressionBuilder,
|
||||
}[] = [
|
||||
...getAbsentObjectTestCases().map((testCase) => ({
|
||||
name: `throws if arguments is ${testCase.valueName}`,
|
||||
context: testCase.absentValue,
|
||||
expectedError: 'missing context',
|
||||
})),
|
||||
{
|
||||
name: 'throws when some of the required args are not provided',
|
||||
sutBuilder: (i: ExpressionBuilder) => i.withParameterNames(['a', 'b', 'c'], false),
|
||||
@@ -159,7 +127,7 @@ describe('Expression', () => {
|
||||
const expected = new PipelineCompilerStub();
|
||||
const context = new ExpressionEvaluationContextStub()
|
||||
.withPipelineCompiler(expected);
|
||||
let actual: IPipelineCompiler;
|
||||
let actual: IPipelineCompiler | undefined;
|
||||
const evaluatorMock: ExpressionEvaluator = (c) => {
|
||||
actual = c.pipelineCompiler;
|
||||
return '';
|
||||
@@ -170,6 +138,7 @@ describe('Expression', () => {
|
||||
// arrange
|
||||
sut.evaluate(context);
|
||||
// assert
|
||||
expectExists(actual);
|
||||
expect(expected).to.equal(actual);
|
||||
});
|
||||
describe('filters unused parameters', () => {
|
||||
@@ -202,7 +171,7 @@ describe('Expression', () => {
|
||||
];
|
||||
for (const testCase of testCases) {
|
||||
it(testCase.name, () => {
|
||||
let actual: IReadOnlyFunctionCallArgumentCollection;
|
||||
let actual: IReadOnlyFunctionCallArgumentCollection | undefined;
|
||||
const evaluatorMock: ExpressionEvaluator = (c) => {
|
||||
actual = c.args;
|
||||
return '';
|
||||
@@ -216,8 +185,10 @@ describe('Expression', () => {
|
||||
// act
|
||||
sut.evaluate(context);
|
||||
// assert
|
||||
const actualArguments = actual.getAllParameterNames()
|
||||
.map((name) => actual.getArgument(name));
|
||||
expectExists(actual);
|
||||
const collection = actual;
|
||||
const actualArguments = collection.getAllParameterNames()
|
||||
.map((name) => collection.getArgument(name));
|
||||
expect(actualArguments).to.deep.equal(testCase.expectedArguments);
|
||||
});
|
||||
}
|
||||
@@ -228,7 +199,7 @@ describe('Expression', () => {
|
||||
class ExpressionBuilder {
|
||||
private position: ExpressionPosition = new ExpressionPosition(0, 5);
|
||||
|
||||
private parameters: IReadOnlyFunctionParameterCollection = new FunctionParameterCollectionStub();
|
||||
private parameters?: IReadOnlyFunctionParameterCollection = new FunctionParameterCollectionStub();
|
||||
|
||||
public withPosition(position: ExpressionPosition) {
|
||||
this.position = position;
|
||||
@@ -240,7 +211,7 @@ class ExpressionBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public withParameters(parameters: IReadOnlyFunctionParameterCollection) {
|
||||
public withParameters(parameters: IReadOnlyFunctionParameterCollection | undefined) {
|
||||
this.parameters = parameters;
|
||||
return this;
|
||||
}
|
||||
@@ -261,5 +232,5 @@ class ExpressionBuilder {
|
||||
return new Expression(this.position, this.evaluator, this.parameters);
|
||||
}
|
||||
|
||||
private evaluator: ExpressionEvaluator = () => '';
|
||||
private evaluator: ExpressionEvaluator = () => `[${ExpressionBuilder.name}] evaluated-expression`;
|
||||
}
|
||||
|
||||
@@ -4,24 +4,10 @@ import { IReadOnlyFunctionCallArgumentCollection } from '@/application/Parser/Sc
|
||||
import { IPipelineCompiler } from '@/application/Parser/Script/Compiler/Expressions/Pipes/IPipelineCompiler';
|
||||
import { FunctionCallArgumentCollectionStub } from '@tests/unit/shared/Stubs/FunctionCallArgumentCollectionStub';
|
||||
import { PipelineCompilerStub } from '@tests/unit/shared/Stubs/PipelineCompilerStub';
|
||||
import { itEachAbsentObjectValue } from '@tests/unit/shared/TestCases/AbsentTests';
|
||||
|
||||
describe('ExpressionEvaluationContext', () => {
|
||||
describe('ctor', () => {
|
||||
describe('args', () => {
|
||||
describe('throws if args is missing', () => {
|
||||
itEachAbsentObjectValue((absentValue) => {
|
||||
// arrange
|
||||
const expectedError = 'missing args, send empty collection instead.';
|
||||
const args = absentValue;
|
||||
// act
|
||||
const act = () => new ExpressionEvaluationContextBuilder()
|
||||
.withArgs(args)
|
||||
.build();
|
||||
// assert
|
||||
expect(act).throw(expectedError);
|
||||
});
|
||||
});
|
||||
it('sets as expected', () => {
|
||||
// arrange
|
||||
const expected = new FunctionCallArgumentCollectionStub()
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { createPositionFromRegexFullMatch } from '@/application/Parser/Script/Compiler/Expressions/Expression/ExpressionPositionFactory';
|
||||
import { ExpressionPosition } from '@/application/Parser/Script/Compiler/Expressions/Expression/ExpressionPosition';
|
||||
|
||||
describe('ExpressionPositionFactory', () => {
|
||||
describe('createPositionFromRegexFullMatch', () => {
|
||||
it(`creates ${ExpressionPosition.name} instance`, () => {
|
||||
// arrange
|
||||
const expectedType = ExpressionPosition;
|
||||
const fakeMatch = createRegexMatch({
|
||||
fullMatch: 'matched string',
|
||||
matchIndex: 5,
|
||||
});
|
||||
// act
|
||||
const position = createPositionFromRegexFullMatch(fakeMatch);
|
||||
// assert
|
||||
expect(position).to.be.instanceOf(expectedType);
|
||||
});
|
||||
|
||||
it('creates a position with the correct start position', () => {
|
||||
// arrange
|
||||
const expectedStartPosition = 5;
|
||||
const fakeMatch = createRegexMatch({
|
||||
fullMatch: 'matched string',
|
||||
matchIndex: expectedStartPosition,
|
||||
});
|
||||
// act
|
||||
const position = createPositionFromRegexFullMatch(fakeMatch);
|
||||
// assert
|
||||
expect(position.start).toBe(expectedStartPosition);
|
||||
});
|
||||
|
||||
it('creates a position with the correct end position', () => {
|
||||
// arrange
|
||||
const startPosition = 3;
|
||||
const matchedString = 'matched string';
|
||||
const expectedEndPosition = startPosition + matchedString.length;
|
||||
const fakeMatch = createRegexMatch({
|
||||
fullMatch: matchedString,
|
||||
matchIndex: startPosition,
|
||||
});
|
||||
// act
|
||||
const position = createPositionFromRegexFullMatch(fakeMatch);
|
||||
// assert
|
||||
expect(position.end).to.equal(expectedEndPosition);
|
||||
});
|
||||
|
||||
it('creates correct position with capturing groups', () => {
|
||||
// arrange
|
||||
const startPosition = 20;
|
||||
const fakeMatch = createRegexMatch({
|
||||
fullMatch: 'matched string',
|
||||
capturingGroups: ['group1', 'group2'],
|
||||
matchIndex: startPosition,
|
||||
});
|
||||
// act
|
||||
const position = createPositionFromRegexFullMatch(fakeMatch);
|
||||
// assert
|
||||
expect(position.start).toBe(startPosition);
|
||||
expect(position.end).toBe(startPosition + fakeMatch[0].length);
|
||||
});
|
||||
|
||||
describe('invalid values', () => {
|
||||
it('throws an error if match.index is undefined', () => {
|
||||
// arrange
|
||||
const fakeMatch = createRegexMatch({
|
||||
fullMatch: 'matched string',
|
||||
matchIndex: undefined,
|
||||
});
|
||||
const expectedError = `Regex match did not yield any results: ${JSON.stringify(fakeMatch)}`;
|
||||
// act
|
||||
const act = () => createPositionFromRegexFullMatch(fakeMatch);
|
||||
// assert
|
||||
expect(act).to.throw(expectedError);
|
||||
});
|
||||
it('throws an error for empty match', () => {
|
||||
// arrange
|
||||
const fakeMatch = createRegexMatch({
|
||||
fullMatch: '',
|
||||
matchIndex: 0,
|
||||
});
|
||||
const expectedError = `Regex match is empty: ${JSON.stringify(fakeMatch)}`;
|
||||
// act
|
||||
const act = () => createPositionFromRegexFullMatch(fakeMatch);
|
||||
// assert
|
||||
expect(act).to.throw(expectedError);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function createRegexMatch(options?: {
|
||||
readonly fullMatch?: string,
|
||||
readonly capturingGroups?: readonly string[],
|
||||
readonly matchIndex?: number,
|
||||
}): RegExpMatchArray {
|
||||
const fullMatch = options?.fullMatch ?? 'fake match';
|
||||
const capturingGroups = options?.capturingGroups ?? [];
|
||||
const fakeMatch: RegExpMatchArray = [fullMatch, ...capturingGroups];
|
||||
fakeMatch.index = options?.matchIndex;
|
||||
return fakeMatch;
|
||||
}
|
||||
@@ -4,22 +4,23 @@ import { IExpressionParser } from '@/application/Parser/Script/Compiler/Expressi
|
||||
import { ExpressionStub } from '@tests/unit/shared/Stubs/ExpressionStub';
|
||||
import { ExpressionParserStub } from '@tests/unit/shared/Stubs/ExpressionParserStub';
|
||||
import { FunctionCallArgumentCollectionStub } from '@tests/unit/shared/Stubs/FunctionCallArgumentCollectionStub';
|
||||
import { itEachAbsentObjectValue, itEachAbsentStringValue } from '@tests/unit/shared/TestCases/AbsentTests';
|
||||
import { itEachAbsentStringValue } from '@tests/unit/shared/TestCases/AbsentTests';
|
||||
import { IExpression } from '@/application/Parser/Script/Compiler/Expressions/Expression/IExpression';
|
||||
|
||||
describe('ExpressionsCompiler', () => {
|
||||
describe('compileExpressions', () => {
|
||||
describe('returns code when code is absent', () => {
|
||||
describe('returns empty string when code is absent', () => {
|
||||
itEachAbsentStringValue((absentValue) => {
|
||||
// arrange
|
||||
const expected = absentValue;
|
||||
const expected = '';
|
||||
const code = absentValue;
|
||||
const sut = new SystemUnderTest();
|
||||
const args = new FunctionCallArgumentCollectionStub();
|
||||
// act
|
||||
const value = sut.compileExpressions(absentValue, args);
|
||||
const value = sut.compileExpressions(code, args);
|
||||
// assert
|
||||
expect(value).to.equal(expected);
|
||||
});
|
||||
}, { excludeNull: true, excludeUndefined: true });
|
||||
});
|
||||
describe('can compile nested expressions', () => {
|
||||
it('when one expression is evaluated to a text that contains another expression', () => {
|
||||
@@ -189,19 +190,6 @@ describe('ExpressionsCompiler', () => {
|
||||
+ `Not equal: ${actualArgs.filter((arg) => arg !== expected)}`,
|
||||
);
|
||||
});
|
||||
describe('throws if arguments is missing', () => {
|
||||
itEachAbsentObjectValue((absentValue) => {
|
||||
// arrange
|
||||
const expectedError = 'missing args, send empty collection instead.';
|
||||
const args = absentValue;
|
||||
const expressionParserMock = new ExpressionParserStub();
|
||||
const sut = new SystemUnderTest(expressionParserMock);
|
||||
// act
|
||||
const act = () => sut.compileExpressions('code', args);
|
||||
// assert
|
||||
expect(act).to.throw(expectedError);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('throws when expressions are invalid', () => {
|
||||
describe('throws when expected argument is not provided but used in code', () => {
|
||||
|
||||
@@ -3,29 +3,20 @@ import { IExpression } from '@/application/Parser/Script/Compiler/Expressions/Ex
|
||||
import { IExpressionParser } from '@/application/Parser/Script/Compiler/Expressions/Parser/IExpressionParser';
|
||||
import { CompositeExpressionParser } from '@/application/Parser/Script/Compiler/Expressions/Parser/CompositeExpressionParser';
|
||||
import { ExpressionStub } from '@tests/unit/shared/Stubs/ExpressionStub';
|
||||
import { itEachAbsentObjectValue } from '@tests/unit/shared/TestCases/AbsentTests';
|
||||
import { itEachAbsentCollectionValue } from '@tests/unit/shared/TestCases/AbsentTests';
|
||||
|
||||
describe('CompositeExpressionParser', () => {
|
||||
describe('ctor', () => {
|
||||
it('throws if null parsers given', () => {
|
||||
// arrange
|
||||
const expectedError = 'missing leafs';
|
||||
const parsers = null;
|
||||
// act
|
||||
const act = () => new CompositeExpressionParser(parsers);
|
||||
// assert
|
||||
expect(act).to.throw(expectedError);
|
||||
});
|
||||
describe('throws if one of the parsers is undefined', () => {
|
||||
itEachAbsentObjectValue((absentValue) => {
|
||||
describe('throws when parsers are missing', () => {
|
||||
itEachAbsentCollectionValue<IExpressionParser>((absentCollection) => {
|
||||
// arrange
|
||||
const expectedError = 'missing leaf';
|
||||
const parsers: readonly IExpressionParser[] = [absentValue, mockParser()];
|
||||
const expectedError = 'missing leafs';
|
||||
const parsers = absentCollection;
|
||||
// act
|
||||
const act = () => new CompositeExpressionParser(parsers);
|
||||
// assert
|
||||
expect(act).to.throw(expectedError);
|
||||
});
|
||||
}, { excludeUndefined: true, excludeNull: true });
|
||||
});
|
||||
});
|
||||
describe('findExpressions', () => {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { IPrimitiveExpression, RegexParser } from '@/application/Parser/Script/C
|
||||
import { ExpressionPosition } from '@/application/Parser/Script/Compiler/Expressions/Expression/ExpressionPosition';
|
||||
import { FunctionParameterStub } from '@tests/unit/shared/Stubs/FunctionParameterStub';
|
||||
import { itEachAbsentStringValue } from '@tests/unit/shared/TestCases/AbsentTests';
|
||||
import { expectExists } from '@tests/shared/Assertions/ExpectExists';
|
||||
|
||||
describe('RegexParser', () => {
|
||||
describe('findExpressions', () => {
|
||||
@@ -16,7 +17,7 @@ describe('RegexParser', () => {
|
||||
const act = () => sut.findExpressions(absentValue);
|
||||
// assert
|
||||
expect(act).to.throw(expectedError);
|
||||
});
|
||||
}, { excludeNull: true, excludeUndefined: true });
|
||||
});
|
||||
it('throws when position is invalid', () => {
|
||||
// arrange
|
||||
@@ -30,17 +31,19 @@ describe('RegexParser', () => {
|
||||
];
|
||||
const sut = new RegexParserConcrete(regexMatchingEmpty);
|
||||
// act
|
||||
let error: string;
|
||||
let errorMessage: string | undefined;
|
||||
try {
|
||||
sut.findExpressions(code);
|
||||
} catch (err) {
|
||||
error = err.message;
|
||||
errorMessage = err.message;
|
||||
}
|
||||
// assert
|
||||
expectExists(errorMessage);
|
||||
const error = errorMessage; // workaround for ts(18048): possibly 'undefined'
|
||||
expect(
|
||||
expectedErrorParts.every((part) => error.includes(part)),
|
||||
`Expected parts: ${expectedErrorParts.join(', ')}`
|
||||
+ `Actual error: ${error}`,
|
||||
+ `Actual error: ${errorMessage}`,
|
||||
);
|
||||
});
|
||||
describe('matches regex as expected', () => {
|
||||
@@ -139,7 +142,7 @@ function mockBuilder(): (match: RegExpMatchArray) => IPrimitiveExpression {
|
||||
});
|
||||
}
|
||||
function getEvaluatorStub(): ExpressionEvaluator {
|
||||
return () => undefined;
|
||||
return () => `[${getEvaluatorStub.name}] evaluated code`;
|
||||
}
|
||||
|
||||
function mockPrimitiveExpression(): IPrimitiveExpression {
|
||||
|
||||
@@ -8,6 +8,12 @@ describe('EscapeDoubleQuotes', () => {
|
||||
const sut = new EscapeDoubleQuotes();
|
||||
// act
|
||||
runPipeTests(sut, [
|
||||
...getAbsentStringTestCases({ excludeNull: true, excludeUndefined: true })
|
||||
.map((testCase) => ({
|
||||
name: 'returns as it is when if input is missing',
|
||||
input: testCase.absentValue,
|
||||
expectedOutput: testCase.absentValue,
|
||||
})),
|
||||
{
|
||||
name: 'using "',
|
||||
input: 'hello "world"',
|
||||
@@ -23,10 +29,5 @@ describe('EscapeDoubleQuotes', () => {
|
||||
input: '""hello world""',
|
||||
expectedOutput: '"^"""^""hello world"^"""^""',
|
||||
},
|
||||
...getAbsentStringTestCases().map((testCase) => ({
|
||||
name: 'returns as it is when if input is missing',
|
||||
input: testCase.absentValue,
|
||||
expectedOutput: testCase.absentValue,
|
||||
})),
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { describe } from 'vitest';
|
||||
import { InlinePowerShell } from '@/application/Parser/Script/Compiler/Expressions/Pipes/PipeDefinitions/InlinePowerShell';
|
||||
import { getAbsentStringTestCases } from '@tests/unit/shared/TestCases/AbsentTests';
|
||||
import { IPipeTestCase, runPipeTests } from './PipeTestRunner';
|
||||
|
||||
describe('InlinePowerShell', () => {
|
||||
@@ -7,11 +8,12 @@ describe('InlinePowerShell', () => {
|
||||
const sut = new InlinePowerShell();
|
||||
// act
|
||||
runPipeTests(sut, [
|
||||
{
|
||||
name: 'returns undefined when if input is undefined',
|
||||
input: undefined,
|
||||
expectedOutput: undefined,
|
||||
},
|
||||
...getAbsentStringTestCases({ excludeNull: true, excludeUndefined: true })
|
||||
.map((testCase) => ({
|
||||
name: 'returns as it is when if input is missing',
|
||||
input: testCase.absentValue,
|
||||
expectedOutput: '',
|
||||
})),
|
||||
...prefixTests('newline', getNewLineCases()),
|
||||
...prefixTests('comment', getCommentCases()),
|
||||
...prefixTests('here-string', hereStringCases()),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { PipeFactory } from '@/application/Parser/Script/Compiler/Expressions/Pipes/PipeFactory';
|
||||
import { PipeStub } from '@tests/unit/shared/Stubs/PipeStub';
|
||||
import { getAbsentStringTestCases, itEachAbsentObjectValue } from '@tests/unit/shared/TestCases/AbsentTests';
|
||||
import { getAbsentStringTestCases } from '@tests/unit/shared/TestCases/AbsentTests';
|
||||
|
||||
describe('PipeFactory', () => {
|
||||
describe('ctor', () => {
|
||||
@@ -19,26 +19,6 @@ describe('PipeFactory', () => {
|
||||
// expect
|
||||
expect(act).to.throw(expectedError);
|
||||
});
|
||||
describe('throws when a pipe is missing', () => {
|
||||
itEachAbsentObjectValue((absentValue) => {
|
||||
// arrange
|
||||
const expectedError = 'missing pipe in list';
|
||||
const pipes = [new PipeStub(), absentValue];
|
||||
// act
|
||||
const act = () => new PipeFactory(pipes);
|
||||
// expect
|
||||
expect(act).to.throw(expectedError);
|
||||
});
|
||||
});
|
||||
it('throws when pipes are null', () => {
|
||||
// arrange
|
||||
const expectedError = 'missing pipes';
|
||||
const pipes = null;
|
||||
// act
|
||||
const act = () => new PipeFactory(pipes);
|
||||
// expect
|
||||
expect(act).to.throw(expectedError);
|
||||
});
|
||||
describe('throws when name is invalid', () => {
|
||||
// act
|
||||
const act = (invalidName: string) => new PipeFactory([new PipeStub().withName(invalidName)]);
|
||||
@@ -82,11 +62,12 @@ describe('PipeFactory', () => {
|
||||
function testPipeNameValidation(testRunner: (invalidName: string) => void) {
|
||||
const testCases = [
|
||||
// Validate missing value
|
||||
...getAbsentStringTestCases().map((testCase) => ({
|
||||
name: `empty pipe name (${testCase.valueName})`,
|
||||
value: testCase.absentValue,
|
||||
expectedError: 'empty pipe name',
|
||||
})),
|
||||
...getAbsentStringTestCases({ excludeNull: true, excludeUndefined: true })
|
||||
.map((testCase) => ({
|
||||
name: `empty pipe name (${testCase.valueName})`,
|
||||
value: testCase.absentValue,
|
||||
expectedError: 'empty pipe name',
|
||||
})),
|
||||
// Validate camelCase
|
||||
...[
|
||||
'PascalCase',
|
||||
|
||||
@@ -10,21 +10,23 @@ describe('PipelineCompiler', () => {
|
||||
describe('compile', () => {
|
||||
describe('throws for invalid arguments', () => {
|
||||
interface ITestCase {
|
||||
name: string;
|
||||
act: (test: PipelineTestRunner) => PipelineTestRunner;
|
||||
expectedError: string;
|
||||
readonly name: string;
|
||||
readonly act: (test: PipelineTestRunner) => PipelineTestRunner;
|
||||
readonly expectedError: string;
|
||||
}
|
||||
const testCases: ITestCase[] = [
|
||||
...getAbsentStringTestCases().map((testCase) => ({
|
||||
name: `"value" is ${testCase.valueName}`,
|
||||
act: (test) => test.withValue(testCase.absentValue),
|
||||
expectedError: 'missing value',
|
||||
})),
|
||||
...getAbsentStringTestCases().map((testCase) => ({
|
||||
name: `"pipeline" is ${testCase.valueName}`,
|
||||
act: (test) => test.withPipeline(testCase.absentValue),
|
||||
expectedError: 'missing pipeline',
|
||||
})),
|
||||
...getAbsentStringTestCases({ excludeNull: true, excludeUndefined: true })
|
||||
.map((testCase) => ({
|
||||
name: `"value" is ${testCase.valueName}`,
|
||||
act: (test) => test.withValue(testCase.absentValue),
|
||||
expectedError: 'missing value',
|
||||
})),
|
||||
...getAbsentStringTestCases({ excludeNull: true, excludeUndefined: true })
|
||||
.map((testCase) => ({
|
||||
name: `"pipeline" is ${testCase.valueName}`,
|
||||
act: (test) => test.withPipeline(testCase.absentValue),
|
||||
expectedError: 'missing pipeline',
|
||||
})),
|
||||
{
|
||||
name: '"pipeline" does not start with pipe',
|
||||
act: (test) => test.withPipeline('pipeline |'),
|
||||
|
||||
@@ -119,13 +119,14 @@ describe('WithParser', () => {
|
||||
describe('conditional rendering based on argument value', () => {
|
||||
describe('does not render scope', () => {
|
||||
runner.expectResults(
|
||||
...getAbsentStringTestCases().map((testCase) => ({
|
||||
name: `does not render when value is "${testCase.valueName}"`,
|
||||
code: '{{ with $parameter }}dark{{ end }} ',
|
||||
args: (args) => args
|
||||
.withArgument('parameter', testCase.absentValue),
|
||||
expected: [''],
|
||||
})),
|
||||
...getAbsentStringTestCases({ excludeNull: true, excludeUndefined: true })
|
||||
.map((testCase) => ({
|
||||
name: `does not render when value is "${testCase.valueName}"`,
|
||||
code: '{{ with $parameter }}dark{{ end }} ',
|
||||
args: (args) => args
|
||||
.withArgument('parameter', testCase.absentValue),
|
||||
expected: [''],
|
||||
})),
|
||||
{
|
||||
name: 'does not render when argument is not provided',
|
||||
code: '{{ with $parameter }}dark{{ end }}',
|
||||
@@ -136,13 +137,14 @@ describe('WithParser', () => {
|
||||
});
|
||||
describe('renders scope', () => {
|
||||
runner.expectResults(
|
||||
...getAbsentStringTestCases().map((testCase) => ({
|
||||
name: `does not render when value is "${testCase.valueName}"`,
|
||||
code: '{{ with $parameter }}dark{{ end }} ',
|
||||
args: (args) => args
|
||||
.withArgument('parameter', testCase.absentValue),
|
||||
expected: [''],
|
||||
})),
|
||||
...getAbsentStringTestCases({ excludeNull: true, excludeUndefined: true })
|
||||
.map((testCase) => ({
|
||||
name: `does not render when value is "${testCase.valueName}"`,
|
||||
code: '{{ with $parameter }}dark{{ end }} ',
|
||||
args: (args) => args
|
||||
.withArgument('parameter', testCase.absentValue),
|
||||
expected: [''],
|
||||
})),
|
||||
{
|
||||
name: 'does not render when argument is not provided',
|
||||
code: '{{ with $parameter }}dark{{ end }}',
|
||||
|
||||
Reference in New Issue
Block a user