refactor: add ScriptRunner class
Change-Id: I118adb9ec338e88b40321208b84228886bb6b590
diff --git a/jest.config.js b/jest.config.js
index cfbbf85..b394077 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -4,194 +4,9 @@
*/
module.exports = {
- moduleFileExtensions: ['js', 'mjs'],
- testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.m?[jt]sx?$",
- // All imported modules in your tests should be mocked automatically
- // automock: false,
-
- // Stop running tests after `n` failures
- // bail: 0,
-
- // The directory where Jest should store its cached dependency information
- // cacheDirectory: "/private/var/folders/dq/pgsjklbj1sx3mndxpcq41swc0000gn/T/jest_dx",
-
- // Automatically clear mock calls, instances, contexts and results before every test
- // clearMocks: false,
-
- // Indicates whether the coverage information should be collected while executing the test
- // collectCoverage: false,
-
- // An array of glob patterns indicating a set of files for which coverage information should be collected
- // collectCoverageFrom: undefined,
-
- // The directory where Jest should output its coverage files
- // coverageDirectory: undefined,
-
- // An array of regexp pattern strings used to skip coverage collection
- // coveragePathIgnorePatterns: [
- // "/node_modules/"
- // ],
-
- // Indicates which provider should be used to instrument code for coverage
- coverageProvider: "v8",
-
- // A list of reporter names that Jest uses when writing coverage reports
- // coverageReporters: [
- // "json",
- // "text",
- // "lcov",
- // "clover"
- // ],
-
- // An object that configures minimum threshold enforcement for coverage results
- // coverageThreshold: undefined,
-
- // A path to a custom dependency extractor
- // dependencyExtractor: undefined,
-
- // Make calling deprecated APIs throw helpful error messages
- // errorOnDeprecated: false,
-
- // The default configuration for fake timers
- // fakeTimers: {
- // "enableGlobally": false
- // },
-
- // Force coverage collection from ignored files using an array of glob patterns
- // forceCoverageMatch: [],
-
- // A path to a module which exports an async function that is triggered once before all test suites
- // globalSetup: undefined,
-
- // A path to a module which exports an async function that is triggered once after all test suites
- // globalTeardown: undefined,
-
- // A set of global variables that need to be available in all test environments
- // globals: {},
-
- // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.
- // maxWorkers: "50%",
-
- // An array of directory names to be searched recursively up from the requiring module's location
- // moduleDirectories: [
- // "node_modules"
- // ],
-
- // An array of file extensions your modules use
- // moduleFileExtensions: [
- // "js",
- // "mjs",
- // "cjs",
- // "jsx",
- // "ts",
- // "tsx",
- // "json",
- // "node"
- // ],
-
- // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
- // moduleNameMapper: {},
-
- // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
- // modulePathIgnorePatterns: [],
-
- // Activates notifications for test results
- // notify: false,
-
- // An enum that specifies notification mode. Requires { notify: true }
- // notifyMode: "failure-change",
-
- // A preset that is used as a base for Jest's configuration
- // preset: undefined,
-
- // Run tests from one or more projects
- // projects: undefined,
-
- // Use this configuration option to add custom reporters to Jest
- // reporters: undefined,
-
- // Automatically reset mock state before every test
- // resetMocks: false,
-
- // Reset the module registry before running each individual test
- // resetModules: false,
-
- // A path to a custom resolver
- // resolver: undefined,
-
- // Automatically restore mock state and implementation before every test
- // restoreMocks: false,
-
- // The root directory that Jest should scan for tests and modules within
- // rootDir: undefined,
-
- // A list of paths to directories that Jest should use to search for files in
- // roots: [
- // "<rootDir>"
- // ],
-
- // Allows you to use a custom runner instead of Jest's default test runner
- // runner: "jest-runner",
-
- // The paths to modules that run some code to configure or set up the testing environment before each test
- // setupFiles: [],
-
- // A list of paths to modules that run some code to configure or set up the testing framework before each test
- // setupFilesAfterEnv: [],
-
- // The number of seconds after which a test is considered as slow and reported as such in the results.
- // slowTestThreshold: 5,
-
- // A list of paths to snapshot serializer modules Jest should use for snapshot testing
- // snapshotSerializers: [],
-
- // The test environment that will be used for testing
- testEnvironment: "jsdom",
-
- // Options that will be passed to the testEnvironment
- // testEnvironmentOptions: {},
-
- // Adds a location field to test results
- // testLocationInResults: false,
-
- // The glob patterns Jest uses to detect test files
- // testMatch: [
- // "**/__tests__/**/*.[jt]s?(x)",
- // "**/?(*.)+(spec|test).[tj]s?(x)"
- // ],
-
- // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
- // testPathIgnorePatterns: [
- // "/node_modules/"
- // ],
-
- // The regexp pattern or array of patterns that Jest uses to detect test files
- // testRegex: [],
-
- // This option allows the use of a custom results processor
- // testResultsProcessor: undefined,
-
- // This option allows use of a custom test runner
- // testRunner: "jest-circus/runner",
-
- // A map from regular expressions to paths to transformers
- // transform: undefined,
-
- // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
- // transformIgnorePatterns: [
- // "/node_modules/",
- // "\\.pnp\\.[^\\/]+$"
- // ],
-
- // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
- // unmockedModulePathPatterns: undefined,
-
- // Indicates whether each individual test should be reported during the run
- // verbose: undefined,
-
- // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
- // watchPathIgnorePatterns: [],
-
- // Whether to use watchman for file crawling
- // watchman: true,
+ preset : 'ts-jest/presets/js-with-ts-esm',
+ moduleFileExtensions : ['js', 'mjs', 'ts'],
+ testRegex : '(/__tests__/.*|(\\.|/)(test|spec))\\.m?[jt]sx?$',
+ coverageProvider : 'v8',
+ testEnvironment : 'jsdom',
};
diff --git a/package-lock.json b/package-lock.json
index 28b88de..bda2678 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -29,6 +29,7 @@
},
"devDependencies": {
"@babel/plugin-transform-modules-commonjs": "7.24.1",
+ "@jest/globals": "^29.7.0",
"@lit/localize-tools": "0.7.2",
"copy-webpack-plugin": "12.0.2",
"css-loader": "7.1.1",
@@ -42,6 +43,7 @@
"sass": "1.77.0",
"sass-loader": "14.2.1",
"style-loader": "4.0.0",
+ "ts-jest": "^29.1.2",
"ts-loader": "^9.5.1",
"ts-node": "^10.9.2",
"typescript": "^5.4.5",
@@ -342,9 +344,9 @@
}
},
"node_modules/@babel/helper-plugin-utils": {
- "version": "7.24.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz",
- "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==",
+ "version": "7.24.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz",
+ "integrity": "sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ==",
"dev": true,
"engines": {
"node": ">=6.9.0"
@@ -363,39 +365,39 @@
}
},
"node_modules/@babel/helper-split-export-declaration": {
- "version": "7.22.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
- "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
+ "version": "7.24.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz",
+ "integrity": "sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.22.5"
+ "@babel/types": "^7.24.5"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-string-parser": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
- "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
+ "version": "7.24.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz",
+ "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
- "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
+ "version": "7.24.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz",
+ "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-option": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz",
- "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==",
+ "version": "7.23.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz",
+ "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==",
"dev": true,
"engines": {
"node": ">=6.9.0"
@@ -573,12 +575,12 @@
}
},
"node_modules/@babel/plugin-syntax-jsx": {
- "version": "7.23.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz",
- "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==",
+ "version": "7.24.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz",
+ "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==",
"dev": true,
"dependencies": {
- "@babel/helper-plugin-utils": "^7.22.5"
+ "@babel/helper-plugin-utils": "^7.24.0"
},
"engines": {
"node": ">=6.9.0"
@@ -675,12 +677,12 @@
}
},
"node_modules/@babel/plugin-syntax-typescript": {
- "version": "7.23.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz",
- "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==",
+ "version": "7.24.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz",
+ "integrity": "sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==",
"dev": true,
"dependencies": {
- "@babel/helper-plugin-utils": "^7.22.5"
+ "@babel/helper-plugin-utils": "^7.24.0"
},
"engines": {
"node": ">=6.9.0"
@@ -751,13 +753,13 @@
}
},
"node_modules/@babel/types": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
- "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
+ "version": "7.24.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz",
+ "integrity": "sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==",
"dev": true,
"dependencies": {
- "@babel/helper-string-parser": "^7.22.5",
- "@babel/helper-validator-identifier": "^7.22.20",
+ "@babel/helper-string-parser": "^7.24.1",
+ "@babel/helper-validator-identifier": "^7.24.5",
"to-fast-properties": "^2.0.0"
},
"engines": {
@@ -3620,6 +3622,18 @@
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
}
},
+ "node_modules/bs-logger": {
+ "version": "0.2.6",
+ "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz",
+ "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==",
+ "dev": true,
+ "dependencies": {
+ "fast-json-stable-stringify": "2.x"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/bser": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz",
@@ -6303,6 +6317,12 @@
"node": ">=8"
}
},
+ "node_modules/lodash.memoize": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
+ "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==",
+ "dev": true
+ },
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@@ -7680,6 +7700,49 @@
"node": ">=12"
}
},
+ "node_modules/ts-jest": {
+ "version": "29.1.2",
+ "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.2.tgz",
+ "integrity": "sha512-br6GJoH/WUX4pu7FbZXuWGKGNDuU7b8Uj77g/Sp7puZV6EXzuByl6JrECvm0MzVzSTkSHWTihsXt+5XYER5b+g==",
+ "dev": true,
+ "dependencies": {
+ "bs-logger": "0.x",
+ "fast-json-stable-stringify": "2.x",
+ "jest-util": "^29.0.0",
+ "json5": "^2.2.3",
+ "lodash.memoize": "4.x",
+ "make-error": "1.x",
+ "semver": "^7.5.3",
+ "yargs-parser": "^21.0.1"
+ },
+ "bin": {
+ "ts-jest": "cli.js"
+ },
+ "engines": {
+ "node": "^16.10.0 || ^18.0.0 || >=20.0.0"
+ },
+ "peerDependencies": {
+ "@babel/core": ">=7.0.0-beta.0 <8",
+ "@jest/types": "^29.0.0",
+ "babel-jest": "^29.0.0",
+ "jest": "^29.0.0",
+ "typescript": ">=4.3 <6"
+ },
+ "peerDependenciesMeta": {
+ "@babel/core": {
+ "optional": true
+ },
+ "@jest/types": {
+ "optional": true
+ },
+ "babel-jest": {
+ "optional": true
+ },
+ "esbuild": {
+ "optional": true
+ }
+ }
+ },
"node_modules/ts-loader": {
"version": "9.5.1",
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz",
@@ -8520,9 +8583,9 @@
}
},
"@babel/helper-plugin-utils": {
- "version": "7.24.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz",
- "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==",
+ "version": "7.24.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz",
+ "integrity": "sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ==",
"dev": true
},
"@babel/helper-simple-access": {
@@ -8535,30 +8598,30 @@
}
},
"@babel/helper-split-export-declaration": {
- "version": "7.22.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
- "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
+ "version": "7.24.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz",
+ "integrity": "sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==",
"dev": true,
"requires": {
- "@babel/types": "^7.22.5"
+ "@babel/types": "^7.24.5"
}
},
"@babel/helper-string-parser": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
- "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
+ "version": "7.24.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz",
+ "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==",
"dev": true
},
"@babel/helper-validator-identifier": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
- "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
+ "version": "7.24.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz",
+ "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==",
"dev": true
},
"@babel/helper-validator-option": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz",
- "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==",
+ "version": "7.23.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz",
+ "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==",
"dev": true
},
"@babel/helpers": {
@@ -8693,12 +8756,12 @@
}
},
"@babel/plugin-syntax-jsx": {
- "version": "7.23.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz",
- "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==",
+ "version": "7.24.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz",
+ "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==",
"dev": true,
"requires": {
- "@babel/helper-plugin-utils": "^7.22.5"
+ "@babel/helper-plugin-utils": "^7.24.0"
}
},
"@babel/plugin-syntax-logical-assignment-operators": {
@@ -8765,12 +8828,12 @@
}
},
"@babel/plugin-syntax-typescript": {
- "version": "7.23.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz",
- "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==",
+ "version": "7.24.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz",
+ "integrity": "sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==",
"dev": true,
"requires": {
- "@babel/helper-plugin-utils": "^7.22.5"
+ "@babel/helper-plugin-utils": "^7.24.0"
}
},
"@babel/plugin-transform-modules-commonjs": {
@@ -8822,13 +8885,13 @@
}
},
"@babel/types": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
- "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
+ "version": "7.24.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz",
+ "integrity": "sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==",
"dev": true,
"requires": {
- "@babel/helper-string-parser": "^7.22.5",
- "@babel/helper-validator-identifier": "^7.22.20",
+ "@babel/helper-string-parser": "^7.24.1",
+ "@babel/helper-validator-identifier": "^7.24.5",
"to-fast-properties": "^2.0.0"
}
},
@@ -11199,6 +11262,15 @@
"update-browserslist-db": "^1.0.13"
}
},
+ "bs-logger": {
+ "version": "0.2.6",
+ "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz",
+ "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==",
+ "dev": true,
+ "requires": {
+ "fast-json-stable-stringify": "2.x"
+ }
+ },
"bser": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz",
@@ -13219,6 +13291,12 @@
"p-locate": "^4.1.0"
}
},
+ "lodash.memoize": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
+ "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==",
+ "dev": true
+ },
"lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@@ -14154,6 +14232,22 @@
"punycode": "^2.1.1"
}
},
+ "ts-jest": {
+ "version": "29.1.2",
+ "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.2.tgz",
+ "integrity": "sha512-br6GJoH/WUX4pu7FbZXuWGKGNDuU7b8Uj77g/Sp7puZV6EXzuByl6JrECvm0MzVzSTkSHWTihsXt+5XYER5b+g==",
+ "dev": true,
+ "requires": {
+ "bs-logger": "0.x",
+ "fast-json-stable-stringify": "2.x",
+ "jest-util": "^29.0.0",
+ "json5": "^2.2.3",
+ "lodash.memoize": "4.x",
+ "make-error": "1.x",
+ "semver": "^7.5.3",
+ "yargs-parser": "^21.0.1"
+ }
+ },
"ts-loader": {
"version": "9.5.1",
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz",
diff --git a/package.json b/package.json
index bcfe8a9..c9f0839 100644
--- a/package.json
+++ b/package.json
@@ -26,6 +26,7 @@
],
"devDependencies": {
"@babel/plugin-transform-modules-commonjs": "7.24.1",
+ "@jest/globals": "^29.7.0",
"@lit/localize-tools": "0.7.2",
"copy-webpack-plugin": "12.0.2",
"css-loader": "7.1.1",
@@ -39,6 +40,7 @@
"sass": "1.77.0",
"sass-loader": "14.2.1",
"style-loader": "4.0.0",
+ "ts-jest": "^29.1.2",
"ts-loader": "^9.5.1",
"ts-node": "^10.9.2",
"typescript": "^5.4.5",
diff --git a/src/common/architecture/scripts/ScriptRunner.test.ts b/src/common/architecture/scripts/ScriptRunner.test.ts
new file mode 100644
index 0000000..7435c8e
--- /dev/null
+++ b/src/common/architecture/scripts/ScriptRunner.test.ts
@@ -0,0 +1,83 @@
+import Script, {
+ ScriptEnvironment,
+ ScriptPage,
+ ScriptRunPhase,
+} from './Script';
+import { beforeEach, expect, it, jest } from '@jest/globals';
+import ScriptRunner from './ScriptRunner';
+
+interface FakeScriptOptions {
+ id: string;
+ priority: number;
+}
+
+class FakeScript extends Script {
+ id: string;
+ priority: number;
+ page: ScriptPage.CommunityConsole;
+ environment: ScriptEnvironment.ContentScript;
+ runPhase: ScriptRunPhase.Main;
+
+ constructor(options: FakeScriptOptions) {
+ super();
+ this.id = options.id;
+ this.priority = options.priority;
+ }
+
+ execute() {}
+}
+
+const fakeScriptMock = jest
+ .spyOn(FakeScript.prototype, 'execute')
+ .mockImplementation(function() {
+ return (this as FakeScript).id;
+ });
+
+beforeEach(() => {
+ jest.clearAllMocks();
+});
+
+it('scripts run in the correct order based on priority', () => {
+ const scriptsConfig = [
+ {
+ script: new FakeScript({
+ id: '1',
+ priority: 1,
+ }),
+ expectedRunPosition: 2,
+ },
+ {
+ script: new FakeScript({
+ id: '2',
+ priority: 1000,
+ }),
+ expectedRunPosition: 3,
+ },
+ {
+ script: new FakeScript({
+ id: '3',
+ priority: 0,
+ }),
+ expectedRunPosition: 1,
+ },
+ {
+ script: new FakeScript({
+ id: '4',
+ priority: 2 ** 31,
+ }),
+ expectedRunPosition: 4,
+ },
+ ];
+
+ const scriptRunner = new ScriptRunner();
+ scriptRunner.add(...scriptsConfig.map((config) => config.script));
+ scriptRunner.run();
+
+ expect(fakeScriptMock).toHaveBeenCalledTimes(scriptsConfig.length);
+ for (const config of scriptsConfig) {
+ expect(fakeScriptMock).toHaveNthReturnedWith(
+ config.expectedRunPosition,
+ config.script.id,
+ );
+ }
+});
diff --git a/src/common/architecture/scripts/ScriptRunner.ts b/src/common/architecture/scripts/ScriptRunner.ts
new file mode 100644
index 0000000..4a2ed2d
--- /dev/null
+++ b/src/common/architecture/scripts/ScriptRunner.ts
@@ -0,0 +1,20 @@
+import Script from './Script';
+
+export default class ScriptRunner {
+ private scripts: Script[] = [];
+
+ add(...scripts: Script[]) {
+ this.scripts.push(...scripts);
+ }
+
+ run() {
+ this.scripts.sort((a, b) => {
+ if (a.priority < b.priority) return -1;
+ if (a.priority > b.priority) return 1;
+ return 0;
+ });
+ for (const script of this.scripts) {
+ script.execute();
+ }
+ }
+}
diff --git a/src/features/Features.ts b/src/features/Features.ts
index 98a4b96..8a13700 100644
--- a/src/features/Features.ts
+++ b/src/features/Features.ts
@@ -4,6 +4,7 @@
ScriptPage,
ScriptRunPhase,
} from '../common/architecture/scripts/Script';
+import ScriptRunner from '../common/architecture/scripts/ScriptRunner';
import AutoRefreshFeature from './autoRefresh/autoRefresh.feature';
import InfiniteScrollFeature from './infiniteScroll/infiniteScroll.feature';
@@ -22,13 +23,11 @@
];
private initializedFeatures: Feature[];
- runScripts(context: Context) {
- const scripts = this.getScripts(context).sort((a, b) =>
- a.priority < b.priority ? -1 : 1,
- );
- for (const script of scripts) {
- script.execute();
- }
+ getScriptRunner(context: Context) {
+ const scripts = this.getScripts(context);
+ const scriptRunner = new ScriptRunner();
+ scriptRunner.add(...scripts);
+ return scriptRunner;
}
getScripts(context: Context) {
diff --git a/src/platforms/communityConsole/entryPoints/main.ts b/src/platforms/communityConsole/entryPoints/main.ts
index c7d223b..03d5eba 100644
--- a/src/platforms/communityConsole/entryPoints/main.ts
+++ b/src/platforms/communityConsole/entryPoints/main.ts
@@ -4,13 +4,18 @@
ScriptRunPhase,
} from '../../../common/architecture/scripts/Script';
import Features from '../../../features/Features';
+import ScriptRunner from '../../../common/architecture/scripts/ScriptRunner';
// Run legacy Javascript entry point
import '../../../contentScripts/communityConsole/main';
const features = new Features();
-features.runScripts({
+const scripts = features.getScripts({
page: ScriptPage.CommunityConsole,
environment: ScriptEnvironment.ContentScript,
runPhase: ScriptRunPhase.Main,
});
+
+const scriptRunner = new ScriptRunner();
+scriptRunner.add(...scripts);
+scriptRunner.run();
diff --git a/src/platforms/communityConsole/entryPoints/start.ts b/src/platforms/communityConsole/entryPoints/start.ts
index b7cb6eb..2410f2c 100644
--- a/src/platforms/communityConsole/entryPoints/start.ts
+++ b/src/platforms/communityConsole/entryPoints/start.ts
@@ -4,13 +4,18 @@
ScriptRunPhase,
} from '../../../common/architecture/scripts/Script';
import Features from '../../../features/Features';
+import ScriptRunner from '../../../common/architecture/scripts/ScriptRunner';
// Run legacy Javascript entry point
import '../../../contentScripts/communityConsole/start';
const features = new Features();
-features.runScripts({
+const scripts = features.getScripts({
page: ScriptPage.CommunityConsole,
environment: ScriptEnvironment.ContentScript,
runPhase: ScriptRunPhase.Start,
});
+
+const scriptRunner = new ScriptRunner();
+scriptRunner.add(...scripts);
+scriptRunner.run();
diff --git a/tsconfig.json b/tsconfig.json
index 363c4b1..ae31377 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -7,6 +7,7 @@
"module": "es6",
"target": "es2019",
"moduleResolution": "bundler",
+ "esModuleInterop": true,
"allowJs": true
},
"ts-node": {