add support for different recommendation levels: strict and standard

This commit is contained in:
undergroundwires
2020-10-19 14:51:42 +01:00
parent 978bab0b81
commit 14be3017c5
20 changed files with 954 additions and 654 deletions

View File

@@ -4,6 +4,7 @@ import { parseApplication } from '@/application/Parser/ApplicationParser';
import 'mocha';
import { expect } from 'chai';
import { parseCategory } from '@/application/Parser/CategoryParser';
import { RecommendationLevel } from '@/domain/RecommendationLevel';
describe('ApplicationParser', () => {
describe('parseApplication', () => {
@@ -86,19 +87,22 @@ describe('ApplicationParser', () => {
});
});
function getTestCategory(scriptName = 'testScript'): YamlCategory {
function getTestCategory(scriptPrefix = 'testScript'): YamlCategory {
return {
category: 'category name',
children: [ getTestScript(scriptName) ],
children: [
getTestScript(`${scriptPrefix}-standard`, RecommendationLevel.Standard),
getTestScript(`${scriptPrefix}-strict`, RecommendationLevel.Strict),
],
};
}
function getTestScript(scriptName: string): YamlScript {
function getTestScript(scriptName: string, level: RecommendationLevel = RecommendationLevel.Standard): YamlScript {
return {
name: scriptName,
code: 'script code',
revertCode: 'revert code',
recommend: true,
recommend: RecommendationLevel[level].toLowerCase(),
};
}

View File

@@ -4,6 +4,7 @@ import { parseCategory } from '@/application/Parser/CategoryParser';
import { YamlCategory, CategoryOrScript, YamlScript } from 'js-yaml-loader!./application.yaml';
import { parseScript } from '@/application/Parser/ScriptParser';
import { parseDocUrls } from '@/application/Parser/DocumentationParser';
import { RecommendationLevel } from '@/domain/RecommendationLevel';
describe('CategoryParser', () => {
describe('parseCategory', () => {
@@ -104,6 +105,6 @@ function getTestScript(): YamlScript {
name: 'script name',
code: 'script code',
revertCode: 'revert code',
recommend: true,
recommend: RecommendationLevel[RecommendationLevel.Standard],
};
}

View File

@@ -3,26 +3,116 @@ import 'mocha';
import { expect } from 'chai';
import { parseScript } from '@/application/Parser/ScriptParser';
import { parseDocUrls } from '@/application/Parser/DocumentationParser';
import { RecommendationLevelNames, RecommendationLevel } from '@/domain/RecommendationLevel';
describe('ScriptParser', () => {
describe('parseScript', () => {
it('parseScript parses as expected', () => {
it('parses name as expected', () => {
// arrange
const expected: YamlScript = {
name: 'expected name',
code: 'expected code',
revertCode: 'expected revert code',
docs: ['hello.com'],
recommend: true,
};
const script = getValidScript();
script.name = 'expected-name';
// act
const actual = parseScript(expected);
const actual = parseScript(script);
// assert
expect(actual.name).to.equal(expected.name);
expect(actual.code).to.equal(expected.code);
expect(actual.revertCode).to.equal(expected.revertCode);
expect(actual.documentationUrls).to.deep.equal(parseDocUrls(expected));
expect(actual.isRecommended).to.equal(expected.recommend);
expect(actual.name).to.equal(script.name);
});
it('parses code as expected', () => {
// arrange
const script = getValidScript();
script.code = 'expected-code';
// act
const actual = parseScript(script);
// assert
expect(actual.code).to.equal(script.code);
});
it('parses revertCode as expected', () => {
// arrange
const script = getValidScript();
script.code = 'expected-code';
// act
const actual = parseScript(script);
// assert
expect(actual.revertCode).to.equal(script.revertCode);
});
it('parses docs as expected', () => {
// arrange
const script = getValidScript();
script.docs = [ 'https://expected-doc1.com', 'https://expected-doc2.com' ];
const expected = parseDocUrls(script);
// act
const actual = parseScript(script);
// assert
expect(actual.documentationUrls).to.deep.equal(expected);
});
describe('level', () => {
it('accepts undefined level', () => {
const undefinedLevels: string[] = [ '', undefined ];
undefinedLevels.forEach((undefinedLevel) => {
// arrange
const script = getValidScript();
script.recommend = undefinedLevel;
// act
const actual = parseScript(script);
// assert
expect(actual.level).to.equal(undefined);
});
});
it('throws on unknown level', () => {
// arrange
const unknownLevel = 'boi';
const script = getValidScript();
script.recommend = unknownLevel;
// act
const act = () => parseScript(script);
// assert
expect(act).to.throw(`unknown level: "${unknownLevel}"`);
});
it('throws on non-string type', () => {
const nonStringTypes: any[] = [ 5, true ];
nonStringTypes.forEach((nonStringType) => {
// arrange
const script = getValidScript();
script.recommend = nonStringType;
// act
const act = () => parseScript(script);
// assert
expect(act).to.throw(`level must be a string but it was ${typeof nonStringType}`);
});
});
describe('parses level as expected', () => {
for (const levelText of RecommendationLevelNames) {
it(levelText, () => {
// arrange
const expectedLevel = RecommendationLevel[levelText];
const script = getValidScript();
script.recommend = levelText;
// act
const actual = parseScript(script);
// assert
expect(actual.level).to.equal(expectedLevel);
});
}
});
it('parses level case insensitive', () => {
// arrange
const script = getValidScript();
const expected = RecommendationLevel.Standard;
script.recommend = RecommendationLevel[expected].toUpperCase();
// act
const actual = parseScript(script);
// assert
expect(actual.level).to.equal(expected);
});
});
});
});
function getValidScript(): YamlScript {
return {
name: 'valid-name',
code: 'valid-code',
revertCode: 'expected revert code',
docs: ['hello.com'],
recommend: RecommendationLevel[RecommendationLevel.Standard].toLowerCase(),
};
}

View File

@@ -5,25 +5,79 @@ import 'mocha';
import { expect } from 'chai';
import { ProjectInformation } from '@/domain/ProjectInformation';
import { IProjectInformation } from '@/domain/IProjectInformation';
import { RecommendationLevel, RecommendationLevels } from '@/domain/RecommendationLevel';
describe('Application', () => {
it('getRecommendedScripts returns as expected', () => {
// arrange
const expected = [
new ScriptStub('S3').withIsRecommended(true),
new ScriptStub('S4').withIsRecommended(true),
];
const sut = new Application(createInformation(), [
new CategoryStub(3).withScripts(expected[0], new ScriptStub('S1').withIsRecommended(false)),
new CategoryStub(2).withScripts(expected[1], new ScriptStub('S2').withIsRecommended(false)),
]);
// act
const actual = sut.getRecommendedScripts();
// assert
expect(expected[0]).to.deep.equal(actual[0]);
expect(expected[1]).to.deep.equal(actual[1]);
describe('getScriptsByLevel', () => {
it('filters out scripts without levels', () => {
// arrange
const scriptsWithLevels = RecommendationLevels.map((level, index) =>
new ScriptStub(`Script${index}`).withLevel(level),
);
const toIgnore = new ScriptStub('script-to-ignore').withLevel(undefined);
for (const currentLevel of RecommendationLevels) {
const category = new CategoryStub(0)
.withScripts(...scriptsWithLevels)
.withScript(toIgnore);
const sut = new Application(createInformation(), [category]);
// act
const actual = sut.getScriptsByLevel(currentLevel);
// assert
expect(actual).to.not.include(toIgnore);
}
});
it(`${RecommendationLevel[RecommendationLevel.Standard]} filters ${RecommendationLevel[RecommendationLevel.Strict]}`, () => {
// arrange
const level = RecommendationLevel.Standard;
const expected = [
new ScriptStub('S1').withLevel(level),
new ScriptStub('S2').withLevel(level),
];
const sut = new Application(createInformation(), [
new CategoryStub(3).withScripts(...expected,
new ScriptStub('S3').withLevel(RecommendationLevel.Strict)),
]);
// act
const actual = sut.getScriptsByLevel(level);
// assert
expect(expected).to.deep.equal(actual);
});
it(`${RecommendationLevel[RecommendationLevel.Strict]} includes ${RecommendationLevel[RecommendationLevel.Standard]}`, () => {
// arrange
const level = RecommendationLevel.Strict;
const expected = [
new ScriptStub('S1').withLevel(RecommendationLevel.Standard),
new ScriptStub('S2').withLevel(RecommendationLevel.Strict),
];
const sut = new Application(createInformation(), [
new CategoryStub(3).withScripts(...expected),
]);
// act
const actual = sut.getScriptsByLevel(level);
// assert
expect(expected).to.deep.equal(actual);
});
it('throws when level is undefined', () => {
// arrange
const sut = new Application(createInformation(), [ getCategoryForValidApplication() ]);
// act
const act = () => sut.getScriptsByLevel(undefined);
// assert
expect(act).to.throw('undefined level');
});
it('throws when level is out of range', () => {
// arrange
const invalidValue = 66;
const sut = new Application(createInformation(), [
getCategoryForValidApplication(),
]);
// act
const act = () => sut.getScriptsByLevel(invalidValue);
// assert
expect(act).to.throw(`invalid level: ${invalidValue}`);
});
});
describe('parameter validation', () => {
describe('ctor', () => {
it('cannot construct without categories', () => {
// arrange
const categories = [];
@@ -43,20 +97,24 @@ describe('Application', () => {
// assert
expect(construct).to.throw('Application must consist of at least one script');
});
it('cannot construct without any recommended scripts', () => {
// arrange
const categories = [
new CategoryStub(3).withScripts(new ScriptStub('S1').withIsRecommended(false)),
new CategoryStub(2).withScripts(new ScriptStub('S2').withIsRecommended(false)),
];
// act
function construct() { return new Application(createInformation(), categories); }
// assert
expect(construct).to.throw('Application must consist of at least one recommended script');
describe('cannot construct without any recommended scripts', () => {
for (const missingLevel of RecommendationLevels) {
// arrange
const expectedError = `none of the scripts are recommended as ${RecommendationLevel[missingLevel]}`;
const otherLevels = RecommendationLevels.filter((level) => level !== missingLevel);
const categories = otherLevels.map((level, index) =>
new CategoryStub(index).withScript(new ScriptStub(`Script${index}`).withLevel(level)),
);
// act
const construct = () => new Application(createInformation(), categories);
// assert
expect(construct).to.throw(expectedError);
}
});
it('cannot construct without information', () => {
// arrange
const categories = [new CategoryStub(1).withScripts(new ScriptStub('S1').withIsRecommended(true))];
const categories = [ new CategoryStub(1).withScripts(
new ScriptStub('S1').withLevel(RecommendationLevel.Standard))];
const information = undefined;
// act
function construct() { return new Application(information, categories); }
@@ -64,42 +122,57 @@ describe('Application', () => {
expect(construct).to.throw('info is undefined');
});
});
it('totalScripts counts right', () => {
// arrange
const categories = [
new CategoryStub(1).withScripts(new ScriptStub('S1').withIsRecommended(true)),
new CategoryStub(2).withScripts(new ScriptStub('S2'), new ScriptStub('S3')),
new CategoryStub(3).withCategories(new CategoryStub(4).withScripts(new ScriptStub('S4'))),
];
// act
const sut = new Application(createInformation(), categories);
// assert
expect(sut.totalScripts).to.equal(4);
describe('totalScripts', () => {
it('returns total of initial scripts', () => {
// arrange
const categories = [
new CategoryStub(1).withScripts(
new ScriptStub('S1').withLevel(RecommendationLevel.Standard)),
new CategoryStub(2).withScripts(
new ScriptStub('S2'),
new ScriptStub('S3').withLevel(RecommendationLevel.Strict)),
new CategoryStub(3).withCategories(
new CategoryStub(4).withScripts(new ScriptStub('S4'))),
];
// act
const sut = new Application(createInformation(), categories);
// assert
expect(sut.totalScripts).to.equal(4);
});
});
it('totalCategories counts right', () => {
// arrange
const categories = [
new CategoryStub(1).withScripts(new ScriptStub('S1').withIsRecommended(true)),
new CategoryStub(2).withScripts(new ScriptStub('S2'), new ScriptStub('S3')),
new CategoryStub(3).withCategories(new CategoryStub(4).withScripts(new ScriptStub('S4'))),
];
// act
const sut = new Application(createInformation(), categories);
// assert
expect(sut.totalCategories).to.equal(4);
describe('totalCategories', () => {
it('returns total of initial categories', () => {
// arrange
const categories = [
new CategoryStub(1).withScripts(new ScriptStub('S1').withLevel(RecommendationLevel.Strict)),
new CategoryStub(2).withScripts(new ScriptStub('S2'), new ScriptStub('S3')),
new CategoryStub(3).withCategories(new CategoryStub(4).withScripts(new ScriptStub('S4'))),
];
// act
const sut = new Application(createInformation(), categories);
// assert
expect(sut.totalCategories).to.equal(4);
});
});
it('sets information as expected', () => {
// arrange
const expected = createInformation();
// act
const sut = new Application(
expected,
[new CategoryStub(1).withScripts(new ScriptStub('S1').withIsRecommended(true))]);
// assert
expect(sut.info).to.deep.equal(expected);
describe('info', () => {
it('returns initial information', () => {
// arrange
const expected = createInformation();
// act
const sut = new Application(
expected, [ getCategoryForValidApplication() ]);
// assert
expect(sut.info).to.deep.equal(expected);
});
});
});
function getCategoryForValidApplication() {
return new CategoryStub(1).withScripts(
new ScriptStub('S1').withLevel(RecommendationLevel.Standard),
new ScriptStub('S2').withLevel(RecommendationLevel.Strict));
}
function createInformation(): IProjectInformation {
return new ProjectInformation('name', 'repo', '0.1.0', 'homepage');
}

View File

@@ -0,0 +1,17 @@
import 'mocha';
import { expect } from 'chai';
import { RecommendationLevelNames, RecommendationLevel } from '@/domain/RecommendationLevel';
describe('RecommendationLevel', () => {
describe('RecommendationLevelNames', () => {
// arrange
const expected = [
RecommendationLevel[RecommendationLevel.Strict],
RecommendationLevel[RecommendationLevel.Standard],
];
// act
const actual = RecommendationLevelNames;
// assert
expect(actual).to.have.deep.members(expected);
});
});

View File

@@ -1,6 +1,7 @@
import 'mocha';
import { expect } from 'chai';
import { Script } from '@/domain/Script';
import { RecommendationLevelNames, RecommendationLevel } from '@/domain/RecommendationLevel';
describe('Script', () => {
describe('ctor', () => {
@@ -13,6 +14,11 @@ describe('Script', () => {
const code = 'duplicate\n\n\ntest\nduplicate';
expect(() => createWithCode(code)).to.throw();
});
it('sets as expected', () => {
const expected = 'expected-revert';
const sut = createWithCode(expected);
expect(sut.code).to.equal(expected);
});
});
describe('revertCode', () => {
it('cannot construct with duplicate lines', () => {
@@ -27,6 +33,11 @@ describe('Script', () => {
const code = 'REM';
expect(() => createWithCode(code, code)).to.throw();
});
it('sets as expected', () => {
const expected = 'expected-revert';
const sut = createWithCode('abc', expected);
expect(sut.revertCode).to.equal(expected);
});
});
describe('canRevert', () => {
it('returns false without revert code', () => {
@@ -38,9 +49,28 @@ describe('Script', () => {
expect(sut.canRevert()).to.equal(true);
});
});
describe('level', () => {
it('cannot construct with invalid wrong value', () => {
expect(() => createWithLevel(55)).to.throw('invalid level');
});
it('sets undefined as expected', () => {
const sut = createWithLevel(undefined);
expect(sut.level).to.equal(undefined);
});
it('sets as expected', () => {
for (const expected of RecommendationLevelNames) {
const sut = createWithLevel(RecommendationLevel[expected]);
const actual = RecommendationLevel[sut.level];
expect(actual).to.equal(expected);
}
});
});
});
});
function createWithCode(code: string, revertCode?: string): Script {
return new Script('name', code, revertCode, [], false);
return new Script('name', code, revertCode, [], RecommendationLevel.Standard);
}
function createWithLevel(level: RecommendationLevel): Script {
return new Script('name', 'code', 'revertCode', [], level);
}

View File

@@ -4,199 +4,200 @@ import { ILiquorTreeNode } from 'liquor-tree';
import { NodeType } from '@/presentation/Scripts/ScriptsTree/SelectableTree/Node/INode';
import { getNewState } from '@/presentation/Scripts/ScriptsTree/SelectableTree/LiquorTree/NodeWrapper/NodeStateUpdater';
describe('getNewState', () => {
describe('checked', () => {
describe('script node', () => {
it('true when selected', () => {
// arrange
const node = getScriptNode();
const selectedScriptNodeIds = [ 'a', 'b', node.id, 'c' ];
// act
const state = getNewState(node, selectedScriptNodeIds);
// assert
expect(state.checked).to.equal(true);
describe('NodeStateUpdater', () => {
describe('getNewState', () => {
describe('checked', () => {
describe('script node', () => {
it('true when selected', () => {
// arrange
const node = getScriptNode();
const selectedScriptNodeIds = [ 'a', 'b', node.id, 'c' ];
// act
const state = getNewState(node, selectedScriptNodeIds);
// assert
expect(state.checked).to.equal(true);
});
it('false when unselected', () => {
// arrange
const node = getScriptNode();
const selectedScriptNodeIds = [ 'a', 'b', 'c' ];
// act
const state = getNewState(node, selectedScriptNodeIds);
// assert
expect(state.checked).to.equal(false);
});
});
it('false when unselected', () => {
// arrange
const node = getScriptNode();
const selectedScriptNodeIds = [ 'a', 'b', 'c' ];
// act
const state = getNewState(node, selectedScriptNodeIds);
// assert
expect(state.checked).to.equal(false);
describe('category node', () => {
it('true when every child selected', () => {
// arrange
const node = {
id: '1',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [
{ id: '2',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('a'), getScriptNode('b') ],
},
{ id: '3',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('c') ],
},
],
};
const selectedScriptNodeIds = [ 'a', 'b', 'c' ];
// act
const state = getNewState(node, selectedScriptNodeIds);
// assert
expect(state.checked).to.equal(true);
});
it('false when none of the children is selected', () => {
// arrange
const node = {
id: '1',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [
{ id: '2',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('a'), getScriptNode('b') ],
},
{ id: '3',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('c') ],
},
],
};
const selectedScriptNodeIds = [ 'none', 'of', 'them', 'are', 'selected' ];
// act
const state = getNewState(node, selectedScriptNodeIds);
// assert
expect(state.checked).to.equal(false);
});
it('false when some of the children is selected', () => {
// arrange
const node = {
id: '1',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [
{
id: '2',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('a'), getScriptNode('b') ],
},
{
id: '3',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('c') ],
},
],
};
const selectedScriptNodeIds = [ 'a', 'c', 'unrelated' ];
// act
const state = getNewState(node, selectedScriptNodeIds);
// assert
expect(state.checked).to.equal(false);
});
});
});
describe('category node', () => {
it('true when every child selected', () => {
// arrange
const node = {
id: '1',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [
{ id: '2',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('a'), getScriptNode('b') ],
},
{ id: '3',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('c') ],
},
],
};
const selectedScriptNodeIds = [ 'a', 'b', 'c' ];
// act
const state = getNewState(node, selectedScriptNodeIds);
// assert
expect(state.checked).to.equal(true);
describe('indeterminate', () => {
describe('script node', () => {
it('false when selected', () => {
// arrange
const node = getScriptNode();
const selectedScriptNodeIds = [ 'a', 'b', node.id, 'c' ];
// act
const state = getNewState(node, selectedScriptNodeIds);
// assert
expect(state.indeterminate).to.equal(false);
});
it('false when not selected', () => {
// arrange
const node = getScriptNode();
const selectedScriptNodeIds = [ 'a', 'b', 'c' ];
// act
const state = getNewState(node, selectedScriptNodeIds);
// assert
expect(state.indeterminate).to.equal(false);
});
});
it('false when none of the children is selected', () => {
// arrange
const node = {
id: '1',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [
{ id: '2',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('a'), getScriptNode('b') ],
},
{ id: '3',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('c') ],
},
],
};
const selectedScriptNodeIds = [ 'none', 'of', 'them', 'are', 'selected' ];
// act
const state = getNewState(node, selectedScriptNodeIds);
// assert
expect(state.checked).to.equal(false);
});
it('false when some of the children is selected', () => {
// arrange
const node = {
id: '1',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [
{
id: '2',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('a'), getScriptNode('b') ],
},
{
id: '3',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('c') ],
},
],
};
const selectedScriptNodeIds = [ 'a', 'c', 'unrelated' ];
// act
const state = getNewState(node, selectedScriptNodeIds);
// assert
expect(state.checked).to.equal(false);
});
});
});
describe('indeterminate', () => {
describe('script node', () => {
it('false when selected', () => {
// arrange
const node = getScriptNode();
const selectedScriptNodeIds = [ 'a', 'b', node.id, 'c' ];
// act
const state = getNewState(node, selectedScriptNodeIds);
// assert
expect(state.indeterminate).to.equal(false);
});
it('false when not selected', () => {
// arrange
const node = getScriptNode();
const selectedScriptNodeIds = [ 'a', 'b', 'c' ];
// act
const state = getNewState(node, selectedScriptNodeIds);
// assert
expect(state.indeterminate).to.equal(false);
});
});
describe('category node', () => {
it('false when all children are selected', () => {
// arrange
const node = {
id: '1',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [
{ id: '2',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('a'), getScriptNode('b') ],
},
{ id: '3',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('c') ],
},
],
};
const selectedScriptNodeIds = [ 'a', 'b', 'c' ];
// act
const state = getNewState(node, selectedScriptNodeIds);
// assert
expect(state.indeterminate).to.equal(false);
});
it('true when all some are selected', () => {
// arrange
const node = {
id: '1',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [
{ id: '2',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('a'), getScriptNode('b') ],
},
{ id: '3',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('c') ],
},
],
};
const selectedScriptNodeIds = [ 'a' ];
// act
const state = getNewState(node, selectedScriptNodeIds);
// assert
expect(state.indeterminate).to.equal(true);
});
it('false when no children are selected', () => {
// arrange
const node = {
id: '1',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [
{ id: '2',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('a'), getScriptNode('b') ],
},
{ id: '3',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('c') ],
},
],
};
const selectedScriptNodeIds = [ 'none', 'of', 'them', 'are', 'selected' ];
// act
const state = getNewState(node, selectedScriptNodeIds);
// assert
expect(state.indeterminate).to.equal(false);
describe('category node', () => {
it('false when all children are selected', () => {
// arrange
const node = {
id: '1',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [
{ id: '2',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('a'), getScriptNode('b') ],
},
{ id: '3',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('c') ],
},
],
};
const selectedScriptNodeIds = [ 'a', 'b', 'c' ];
// act
const state = getNewState(node, selectedScriptNodeIds);
// assert
expect(state.indeterminate).to.equal(false);
});
it('true when all some are selected', () => {
// arrange
const node = {
id: '1',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [
{ id: '2',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('a'), getScriptNode('b') ],
},
{ id: '3',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('c') ],
},
],
};
const selectedScriptNodeIds = [ 'a' ];
// act
const state = getNewState(node, selectedScriptNodeIds);
// assert
expect(state.indeterminate).to.equal(true);
});
it('false when no children are selected', () => {
// arrange
const node = {
id: '1',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [
{ id: '2',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('a'), getScriptNode('b') ],
},
{ id: '3',
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
children: [ getScriptNode('c') ],
},
],
};
const selectedScriptNodeIds = [ 'none', 'of', 'them', 'are', 'selected' ];
// act
const state = getNewState(node, selectedScriptNodeIds);
// assert
expect(state.indeterminate).to.equal(false);
});
});
});
});
function getScriptNode(scriptNodeId: string = 'script'): ILiquorTreeNode {
return {
id: scriptNodeId,
data: {
type: NodeType.Script,
documentationUrls: [],
isReversible: false,
},
children: [],
};
}
});
function getScriptNode(scriptNodeId: string = 'script'): ILiquorTreeNode {
return {
id: scriptNodeId,
data: {
type: NodeType.Script,
documentationUrls: [],
isReversible: false,
},
children: [],
};
}

View File

@@ -15,8 +15,8 @@ export class ApplicationStub implements IApplication {
return this.getAllCategories().find(
(category) => category.id === categoryId);
}
public getRecommendedScripts(): readonly IScript[] {
throw new Error('Method not implemented: getRecommendedScripts');
public getScriptsByLevel(): readonly IScript[] {
throw new Error('Method not implemented: getScriptsByLevel');
}
public findScript(scriptId: string): IScript {
return this.getAllScripts().find((script) => scriptId === script.id);

View File

@@ -1,32 +1,37 @@
import { BaseEntity } from '@/infrastructure/Entity/BaseEntity';
import { IScript } from '@/domain/IScript';
import { RecommendationLevel } from '@/domain/RecommendationLevel';
export class ScriptStub extends BaseEntity<string> implements IScript {
public name = `name${this.id}`;
public code = `REM code${this.id}`;
public revertCode = `REM revertCode${this.id}`;
public readonly documentationUrls = new Array<string>();
public isRecommended = true;
public level = RecommendationLevel.Standard;
constructor(public readonly id: string) {
super(id);
}
public canRevert(): boolean {
return Boolean(this.revertCode);
}
public withIsRecommended(value: boolean): ScriptStub {
this.isRecommended = value;
public withLevel(value: RecommendationLevel): ScriptStub {
this.level = value;
return this;
}
public withCode(value: string): ScriptStub {
this.code = value;
return this;
}
public withName(name: string): ScriptStub {
this.name = name;
return this;
}
public withRevertCode(revertCode: string): ScriptStub {
this.revertCode = revertCode;
return this;