diff --git a/packages/api-redundancy/.eslintrc.js b/packages/api-redundancy/.eslintrc.js index 2f308dd..07ef34a 100644 --- a/packages/api-redundancy/.eslintrc.js +++ b/packages/api-redundancy/.eslintrc.js @@ -3,7 +3,7 @@ module.exports = { browser: true, es6: true, node: true, - mocha: true, + jasmine: true, }, extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], globals: { @@ -11,13 +11,10 @@ module.exports = { SharedArrayBuffer: 'readonly', }, parser: '@typescript-eslint/parser', - parserOptions: { - ecmaVersion: 2018, - sourceType: 'module', - project: __dirname + '/tsconfig.json', - }, - plugins: ['@typescript-eslint'], + plugins: ['@typescript-eslint', 'jasmine'], rules: { 'no-mixed-spaces-and-tabs': ['off'], + 'no-unused-vars': ['off'], + '@typescript-eslint/no-unused-vars-experimental': ['error'], }, }; diff --git a/packages/api-redundancy/package-lock.json b/packages/api-redundancy/package-lock.json index 102dda6..9c939c9 100644 --- a/packages/api-redundancy/package-lock.json +++ b/packages/api-redundancy/package-lock.json @@ -1,12 +1,12 @@ { "name": "@iconify/api-redundancy", - "version": "1.0.0", + "version": "1.0.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@iconify/api-redundancy", - "version": "1.0.0", + "version": "1.0.1", "license": "(Apache-2.0 OR GPL-2.0)", "devDependencies": { "@types/jest": "^27.0.1", @@ -15,6 +15,8 @@ "@typescript-eslint/parser": "^4.31.1", "cross-env": "^7.0.3", "eslint": "^7.32.0", + "eslint-plugin-jasmine": "^4.1.2", + "jasmine": "^3.9.0", "jest": "^27.2.0", "ts-jest": "^27.0.5", "tsup": "^5.1.0" @@ -2266,6 +2268,16 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint-plugin-jasmine": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jasmine/-/eslint-plugin-jasmine-4.1.2.tgz", + "integrity": "sha512-Jr52EBi6Ql5WVDvRCKBID9kRD6/CaObvCWmgHpqobczX2Mzt8/QMu9vpgx6q/O5jyQ9CIGrKaEbPuEfHRf8guw==", + "dev": true, + "engines": { + "node": ">=8", + "npm": ">=6" + } + }, "node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -3133,6 +3145,25 @@ "node": ">=8" } }, + "node_modules/jasmine": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-3.9.0.tgz", + "integrity": "sha512-JgtzteG7xnqZZ51fg7N2/wiQmXon09szkALcRMTgCMX4u/m17gVJFjObnvw5FXkZOWuweHPaPRVB6DI2uN0wVA==", + "dev": true, + "dependencies": { + "glob": "^7.1.6", + "jasmine-core": "~3.9.0" + }, + "bin": { + "jasmine": "bin/jasmine.js" + } + }, + "node_modules/jasmine-core": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.9.0.tgz", + "integrity": "sha512-Tv3kVbPCGVrjsnHBZ38NsPU3sDOtNa0XmbG2baiyJqdb5/SPpDO6GVwJYtUryl6KB4q1Ssckwg612ES9Z0dreQ==", + "dev": true + }, "node_modules/jest": { "version": "27.2.0", "resolved": "https://registry.npmjs.org/jest/-/jest-27.2.0.tgz", @@ -7248,6 +7279,12 @@ } } }, + "eslint-plugin-jasmine": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jasmine/-/eslint-plugin-jasmine-4.1.2.tgz", + "integrity": "sha512-Jr52EBi6Ql5WVDvRCKBID9kRD6/CaObvCWmgHpqobczX2Mzt8/QMu9vpgx6q/O5jyQ9CIGrKaEbPuEfHRf8guw==", + "dev": true + }, "eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -7884,6 +7921,22 @@ "istanbul-lib-report": "^3.0.0" } }, + "jasmine": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-3.9.0.tgz", + "integrity": "sha512-JgtzteG7xnqZZ51fg7N2/wiQmXon09szkALcRMTgCMX4u/m17gVJFjObnvw5FXkZOWuweHPaPRVB6DI2uN0wVA==", + "dev": true, + "requires": { + "glob": "^7.1.6", + "jasmine-core": "~3.9.0" + } + }, + "jasmine-core": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.9.0.tgz", + "integrity": "sha512-Tv3kVbPCGVrjsnHBZ38NsPU3sDOtNa0XmbG2baiyJqdb5/SPpDO6GVwJYtUryl6KB4q1Ssckwg612ES9Z0dreQ==", + "dev": true + }, "jest": { "version": "27.2.0", "resolved": "https://registry.npmjs.org/jest/-/jest-27.2.0.tgz", diff --git a/packages/api-redundancy/package.json b/packages/api-redundancy/package.json index 565d491..690e78d 100644 --- a/packages/api-redundancy/package.json +++ b/packages/api-redundancy/package.json @@ -1,17 +1,25 @@ { "name": "@iconify/api-redundancy", "description": "Reusable redundancy library for API queries", - "version": "1.0.0", + "version": "1.0.1", "author": "Vjacheslav Trushkin", "license": "(Apache-2.0 OR GPL-2.0)", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/index.d.ts", + "exports": { + ".": { + "require": "./dist/index.js", + "import": "./dist/index.mjs" + } + }, "scripts": { - "lint": "npx eslint src/*.ts", + "lint": "eslint src/*.ts", "prebuild": "npm run lint", "build": "tsup src/index.ts --dts --format esm,cjs", - "test": "jest --runInBand" + "test:jest": "jest --runInBand", + "test:jasmine": "cross-env NODE_OPTIONS=--experimental-vm-modules npx jasmine", + "test": "npm run test:jest && npm run test:jasmine" }, "bugs": "https://github.com/iconify/iconify/issues", "homepage": "https://iconify.design/", @@ -27,6 +35,8 @@ "@typescript-eslint/parser": "^4.31.1", "cross-env": "^7.0.3", "eslint": "^7.32.0", + "eslint-plugin-jasmine": "^4.1.2", + "jasmine": "^3.9.0", "jest": "^27.2.0", "ts-jest": "^27.0.5", "tsup": "^5.1.0" diff --git a/packages/api-redundancy/spec/redundancySpec.mjs b/packages/api-redundancy/spec/redundancySpec.mjs new file mode 100644 index 0000000..44d58ca --- /dev/null +++ b/packages/api-redundancy/spec/redundancySpec.mjs @@ -0,0 +1,113 @@ +import { initRedundancy } from '@iconify/api-redundancy'; + +describe('Redundancy class', () => { + it('Simple query', (done) => { + const redundancy = initRedundancy({ + resources: [ + 'https://api.local', // Will fail + 'https://api-backup1.local', // Success + 'https://api-backup2.local', + ], + rotate: 20, + timeout: 100, + }); + + // Premade responses + const responses = { + 'https://api-backup1.local/foo': 'foo', + }; + let counter = 0; + let doneCallbackCalled = false; + + const query = redundancy.query( + '/foo', + (resource, payload, status) => { + counter++; + expect(counter).toBeLessThan(3); // No more than 2 queries should be executed + + // Make URI from resource + payload + const uri = resource + payload; + + // Get fake data if it exists + if (responses[uri] === void 0) { + return; + } + + // Do something with "data", simulate instant callback + status.done(responses[uri]); + + // Complete test + setTimeout(() => { + expect(counter).toEqual(2); + expect(doneCallbackCalled).toEqual(true); + expect(query().status).toEqual('completed'); + expect(redundancy.getIndex()).toEqual(1); // Should have changed to 1 after query + done(); + }); + }, + (data) => { + expect(data).toEqual('foo'); + doneCallbackCalled = true; + } + ); + + // Test find() + expect(redundancy.find((item) => item().payload === '/foo')).toEqual( + query + ); + expect(redundancy.find((item) => item().status === 'pending')).toEqual( + query + ); + }); + + it('Different start index', (done) => { + const redundancy = initRedundancy({ + resources: [ + 'https://api.local', + 'https://api-backup1.local', + 'https://api-backup2.local', + ], + rotate: 20, + timeout: 3000, + index: 1, + }); + + // Premade responses + const responses = { + 'https://api-backup1.local/foo': 'foo', + }; + let counter = 0; + + const query = redundancy.query('/foo', (resource, payload, status) => { + counter++; + expect(counter).toBeLessThan(2); // Should be success on first call because start index = 1 + + // Make URI from resource + payload + const uri = resource + payload; + + // Get fake data if it exists + if (responses[uri] === void 0) { + return; + } + + // Do something with "data", simulate instant callback + status.done(responses[uri]); + + // Complete test + setTimeout(() => { + expect(counter).toEqual(1); + expect(query().status).toEqual('completed'); + expect(redundancy.getIndex()).toEqual(1); + done(); + }); + }); + + // Test find() + expect(redundancy.find((item) => item().payload === '/foo')).toEqual( + query + ); + expect(redundancy.find((item) => item().status === 'pending')).toEqual( + query + ); + }); +}); diff --git a/packages/api-redundancy/spec/support/jasmine.json b/packages/api-redundancy/spec/support/jasmine.json new file mode 100644 index 0000000..d2d62fb --- /dev/null +++ b/packages/api-redundancy/spec/support/jasmine.json @@ -0,0 +1,7 @@ +{ + "spec_dir": "spec", + "spec_files": ["**/*[sS]pec.?(m)js"], + "helpers": ["helpers/**/*.?(m)js"], + "stopSpecOnExpectationFailure": false, + "random": true +} diff --git a/packages/api-redundancy/tests/basic-query-test.ts b/packages/api-redundancy/tests/basic-query-test.ts index 9736ff3..3e234d7 100644 --- a/packages/api-redundancy/tests/basic-query-test.ts +++ b/packages/api-redundancy/tests/basic-query-test.ts @@ -2,7 +2,7 @@ import type { RedundancyConfig } from '../src/config'; import { sendQuery } from '../src/query'; describe('Basic queries', () => { - test('Empty query', (done) => { + it('Empty query', (done) => { const payload = {}; const config: RedundancyConfig = { resources: [], diff --git a/packages/api-redundancy/tsconfig.json b/packages/api-redundancy/tsconfig.json index 48dbf87..4832f59 100644 --- a/packages/api-redundancy/tsconfig.json +++ b/packages/api-redundancy/tsconfig.json @@ -1,5 +1,5 @@ { - "include": ["./src/*.ts", "./tests/*.ts"], + "include": ["./src/*.ts", "./tests/*.ts", ".eslintrc.js"], "compilerOptions": { "target": "ESNext", "module": "CommonJS",