UNPKG

@sketch-hq/sketch-assistant-utils

Version:

Utility functions and types for Sketch Assistants.

360 lines (359 loc) 14.9 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const sketch_assistant_types_1 = require("@sketch-hq/sketch-assistant-types"); const sketch_file_1 = require("@sketch-hq/sketch-file"); const path_1 = require("path"); const __1 = require(".."); const get_image_metadata_1 = require("../../../get-image-metadata"); const process_1 = require("../../../process"); const test_helpers_1 = require("../../../test-helpers"); /** * Test helper. */ const testRunMultiple = ({ assistants = { 'dummy-assistant': test_helpers_1.createAssistant() }, cancelToken = { cancelled: false }, getImageMetadata = get_image_metadata_1.getImageMetadata, env = { locale: 'en', runtime: sketch_assistant_types_1.AssistantRuntime.Node }, ignore = { pages: [], assistants: {} }, timeBudgets = { totalMs: Infinity, minRuleTimeoutMs: 0, maxRuleTimeoutMs: Infinity }, }, filename = './empty.sketch') => __awaiter(void 0, void 0, void 0, function* () { const file = yield sketch_file_1.fromFile(path_1.resolve(__dirname, filename)); const processedFile = yield process_1.process(file, cancelToken); return yield __1.runMultipleAssistants({ assistants, processedFile, cancelToken, getImageMetadata, env, ignore, timeBudgets, }); }); test('rejects when no assistants', () => __awaiter(void 0, void 0, void 0, function* () { yield expect(testRunMultiple({ assistants: {} })).rejects.toHaveProperty('code', 'runError'); })); test('outputs an error result for a malformed assistant package', () => __awaiter(void 0, void 0, void 0, function* () { const promise = testRunMultiple({ assistants: { // @ts-ignore foo: {}, }, }); yield expect(promise).resolves.toHaveProperty('assistants.foo.code', 'error'); })); test('outputs an error result for assistant name mismatch', () => __awaiter(void 0, void 0, void 0, function* () { const promise = testRunMultiple({ assistants: { foo: test_helpers_1.createAssistant({ name: 'bar' }), }, }); yield expect(promise).resolves.toHaveProperty('assistants.foo.code', 'error'); })); test('bails early if cancelled', () => __awaiter(void 0, void 0, void 0, function* () { yield expect(testRunMultiple({ cancelToken: { cancelled: true } })).rejects.toHaveProperty('code', 'cancelled'); })); test('works with a no-op assistant', () => __awaiter(void 0, void 0, void 0, function* () { yield expect(testRunMultiple({})).resolves.toBeTruthy(); })); test('works with assistants exported as ESM defaults', () => __awaiter(void 0, void 0, void 0, function* () { const assistants = { 'assistant-2': { __esModule: true, default: [ { __esModule: true, default: test_helpers_1.createAssistant({ name: 'assistant-1' }), }, { __esModule: true, default: test_helpers_1.createAssistant({ name: 'assistant-2' }), }, ], }, }; const output = yield testRunMultiple({ assistants }); expect(output.assistants['assistant-2'].code).toBe('success'); })); test('can generate violations', () => __awaiter(void 0, void 0, void 0, function* () { const assistants = { 'dummy-assistant': test_helpers_1.createAssistant({ rules: [ test_helpers_1.createRule({ name: 'rule', rule: (ruleContext) => __awaiter(void 0, void 0, void 0, function* () { ruleContext.utils.report('Subspace anomaly detected'); }), }), ], config: test_helpers_1.createAssistantConfig({ rules: { rule: { active: true }, }, }), }), }; const output = yield testRunMultiple({ assistants }); const res = output.assistants['dummy-assistant']; expect.assertions(3); expect(res).toHaveProperty('code', 'success'); expect(res).toHaveProperty('result.passed', false); if (res.code === 'success') { expect(res.result.violations).toHaveLength(1); } })); test('will pass an assistant if violations not error-level', () => __awaiter(void 0, void 0, void 0, function* () { const assistants = { 'dummy-assistant': test_helpers_1.createAssistant({ rules: [ test_helpers_1.createRule({ name: 'rule', rule: (ruleContext) => __awaiter(void 0, void 0, void 0, function* () { ruleContext.utils.report('Subspace anomaly detected'); }), }), ], config: test_helpers_1.createAssistantConfig({ rules: { rule: { active: true, severity: sketch_assistant_types_1.ViolationSeverity.info }, }, }), }), }; const output = yield testRunMultiple({ assistants }); const res = output.assistants['dummy-assistant']; expect.assertions(3); expect(res).toHaveProperty('code', 'success'); expect(res).toHaveProperty('result.passed', true); if (res.code === 'success') { expect(res.result.violations).toHaveLength(1); } })); test('can generate rule errors', () => __awaiter(void 0, void 0, void 0, function* () { const assistants = { 'dummy-assistant': test_helpers_1.createAssistant({ rules: [ test_helpers_1.createRule({ name: 'rule', rule: () => __awaiter(void 0, void 0, void 0, function* () { throw new Error(); }), }), ], config: test_helpers_1.createAssistantConfig({ rules: { rule: { active: true, severity: sketch_assistant_types_1.ViolationSeverity.warn }, }, }), }), }; const output = yield testRunMultiple({ assistants }); const res = output.assistants['dummy-assistant']; expect.assertions(2); if (res.code === 'success') { expect(res.result.violations).toHaveLength(0); expect(res.result.ruleErrors).toHaveLength(1); } })); test('generates rule errors when ignored objects are reported', () => __awaiter(void 0, void 0, void 0, function* () { const assistants = { 'dummy-assistant': test_helpers_1.createAssistant({ rules: [ test_helpers_1.createRule({ name: 'rule', rule: (context) => __awaiter(void 0, void 0, void 0, function* () { context.utils.report('', context.file.original.contents.document.pages[0]); }), }), ], config: test_helpers_1.createAssistantConfig({ rules: { rule: { active: true }, }, }), }), }; const output = yield testRunMultiple({ assistants, ignore: { pages: [], assistants: { 'dummy-assistant': { rules: { rule: { objects: ['9AD22B94-A05B-4F49-8EDD-A38D62BD6181'] } }, }, }, }, }); const res = output.assistants['dummy-assistant']; expect.assertions(2); if (res.code === 'success') { expect(res.result.violations).toHaveLength(0); expect(res.result.ruleErrors).toHaveLength(1); } })); test.only('budget can be used to timeout rules', () => __awaiter(void 0, void 0, void 0, function* () { const assistants = { 'dummy-assistant': test_helpers_1.createAssistant({ rules: [ test_helpers_1.createRule({ name: 'rule', rule: () => __awaiter(void 0, void 0, void 0, function* () { yield new Promise((resolve) => setTimeout(resolve, 100)); }), }), ], config: test_helpers_1.createAssistantConfig({ rules: { rule: { active: true }, }, }), }), }; const output = yield testRunMultiple({ assistants, timeBudgets: { totalMs: Infinity, minRuleTimeoutMs: 0, maxRuleTimeoutMs: 10, }, }); const res = output.assistants['dummy-assistant']; expect.assertions(2); if (res.code === 'success') { expect(res.result.violations).toHaveLength(0); expect(res.result.ruleErrors).toHaveLength(1); } })); test('can run mulitple assistants', () => __awaiter(void 0, void 0, void 0, function* () { const assistants = { 'dummy-assistant-1': test_helpers_1.createAssistant({ name: 'dummy-assistant-1', rules: [ test_helpers_1.createRule({ name: 'dummy-assistant-1/rule', rule: (ruleContext) => __awaiter(void 0, void 0, void 0, function* () { ruleContext.utils.report(''); }), }), ], config: test_helpers_1.createAssistantConfig({ rules: { 'dummy-assistant-1/rule': { active: true }, }, }), }), 'dummy-assistant-2': test_helpers_1.createAssistant({ name: 'dummy-assistant-2', rules: [ test_helpers_1.createRule({ name: 'dummy-assistant-2/rule', rule: (ruleContext) => __awaiter(void 0, void 0, void 0, function* () { ruleContext.utils.report(''); }), }), ], config: test_helpers_1.createAssistantConfig({ rules: { 'dummy-assistant-2/rule': { active: true }, }, }), }), }; const output = yield testRunMultiple({ assistants }); const res1 = output.assistants['dummy-assistant-1']; const res2 = output.assistants['dummy-assistant-2']; expect.assertions(4); if (res1.code === 'success') { expect(res1.result.violations).toHaveLength(1); expect(res1.result.ruleErrors).toHaveLength(0); } if (res2.code === 'success') { expect(res2.result.violations).toHaveLength(1); expect(res2.result.ruleErrors).toHaveLength(0); } })); test('can be internationalized', () => __awaiter(void 0, void 0, void 0, function* () { const assistant = (env) => __awaiter(void 0, void 0, void 0, function* () { return ({ name: 'dummy-assistant', rules: [ test_helpers_1.createRule({ name: 'rule', rule: (ruleContext) => __awaiter(void 0, void 0, void 0, function* () { ruleContext.utils.report(env.locale === 'zh-Hans' ? '你好世界' : 'Hello world'); }), }), ], config: { rules: { rule: { active: true }, }, }, }); }); const assistants = { 'dummy-assistant': assistant, }; const zhOutput = yield testRunMultiple({ assistants, env: { runtime: sketch_assistant_types_1.AssistantRuntime.Node, locale: 'zh-Hans' }, }); const zhRes = zhOutput.assistants['dummy-assistant']; const enOutput = yield testRunMultiple({ assistants, env: { runtime: sketch_assistant_types_1.AssistantRuntime.Node, locale: 'en' }, }); const enRes = enOutput.assistants['dummy-assistant']; expect.assertions(2); if (zhRes.code === 'success' && enRes.code === 'success') { expect(zhRes.result.violations[0].message).toBe('你好世界'); expect(enRes.result.violations[0].message).toBe('Hello world'); } })); test('prunes missing assistants from ignore data', () => __awaiter(void 0, void 0, void 0, function* () { const { ignore } = yield testRunMultiple({ ignore: { pages: [], assistants: { 'missing-assistant': { rules: {} }, 'dummy-assistant': { rules: {} } }, }, }); expect(ignore.assistants).not.toHaveProperty('missing-assistant'); expect(ignore.assistants).toHaveProperty('dummy-assistant'); })); test('prunes missing rules from ignore data', () => __awaiter(void 0, void 0, void 0, function* () { const { ignore } = yield testRunMultiple({ assistants: { 'dummy-assistant': test_helpers_1.createAssistant({ rules: [test_helpers_1.createRule({ name: 'rule' })] }), }, ignore: { pages: [], assistants: { 'dummy-assistant': { rules: { rule: { allObjects: true }, missing: { allObjects: true } } }, }, }, }); expect(ignore.assistants['dummy-assistant'].rules).toHaveProperty('rule'); expect(ignore.assistants['dummy-assistant'].rules).not.toHaveProperty('missing'); })); test('prunes missing objects from ignore data', () => __awaiter(void 0, void 0, void 0, function* () { const { ignore } = yield testRunMultiple({ assistants: { 'dummy-assistant': test_helpers_1.createAssistant({ rules: [test_helpers_1.createRule({ name: 'rule' })] }), }, ignore: { pages: [], assistants: { 'dummy-assistant': { rules: { rule: { objects: ['9AD22B94-A05B-4F49-8EDD-A38D62BD6181', 'missing-id'] } }, }, }, }, }); expect.assertions(2); if ('objects' in ignore.assistants['dummy-assistant'].rules.rule) { expect(ignore.assistants['dummy-assistant'].rules.rule.objects).toContain('9AD22B94-A05B-4F49-8EDD-A38D62BD6181'); expect(ignore.assistants['dummy-assistant'].rules.rule.objects).not.toContain('missing-id'); } }));