mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-02-26 10:52:20 +00:00
feat: tests
This commit is contained in:
@@ -22,11 +22,11 @@
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsup --dts",
|
||||
"format": "prettier .",
|
||||
"format:fix": "prettier --write .",
|
||||
"format": "prettier . --ignore-path ../../.gitignore",
|
||||
"format:fix": "prettier --write . --ignore-path ../../.gitignore",
|
||||
"lint": "eslint --ext .ts src/",
|
||||
"lint:fix": "eslint --fix --ext .ts src/",
|
||||
"test": "nyc mocha 'test/**/*.spec.ts'"
|
||||
"test": "c8 mocha"
|
||||
},
|
||||
"dependencies": {
|
||||
"@krlwlfrt/async-pool": "0.7.0",
|
||||
@@ -58,7 +58,6 @@
|
||||
"@openstapps/nyc-config": "workspace:*",
|
||||
"@openstapps/prettier-config": "workspace:*",
|
||||
"@openstapps/tsconfig": "workspace:*",
|
||||
"@testdeck/mocha": "0.3.3",
|
||||
"@types/body-parser": "1.19.2",
|
||||
"@types/chai": "4.3.5",
|
||||
"@types/chai-as-promised": "7.1.5",
|
||||
@@ -75,7 +74,7 @@
|
||||
"fs-extra": "10.1.0",
|
||||
"mocha": "10.2.0",
|
||||
"nock": "13.3.1",
|
||||
"nyc": "15.1.0",
|
||||
"c8": "7.13.0",
|
||||
"ts-node": "10.9.1",
|
||||
"tsup": "6.7.0",
|
||||
"typedoc": "0.23.28",
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
export * from './bulk.js'
|
||||
export * from './client.js'
|
||||
export * from './connector-client.js'
|
||||
export * from './copy.js'
|
||||
export * from './e2e.js'
|
||||
export * from './errors.js'
|
||||
export * from './http-client.js'
|
||||
export * from './http-client-interface.js'
|
||||
export * from './plugin.js'
|
||||
export * from './plugin-client.js'
|
||||
export * from './bulk.js';
|
||||
export * from './client.js';
|
||||
export * from './connector-client.js';
|
||||
export * from './copy.js';
|
||||
export * from './e2e.js';
|
||||
export * from './errors.js';
|
||||
export * from './http-client.js';
|
||||
export * from './http-client-interface.js';
|
||||
export * from './plugin.js';
|
||||
export * from './plugin-client.js';
|
||||
|
||||
@@ -24,29 +24,27 @@ import {expect} from 'chai';
|
||||
import chai from 'chai';
|
||||
import chaiAsPromised from 'chai-as-promised';
|
||||
import chaiSpies from 'chai-spies';
|
||||
import {suite, test} from '@testdeck/mocha';
|
||||
import moment from 'moment';
|
||||
import {Bulk} from '../src/bulk.js';
|
||||
import {Client} from '../src/client.js';
|
||||
import {BulkWithMultipleTypesError} from '../src/errors.js';
|
||||
import {HttpClient} from '../src/http-client.js';
|
||||
import {HttpClient, Bulk, Client, BulkWithMultipleTypesError} from '../src/index.js';
|
||||
|
||||
chai.should();
|
||||
chai.use(chaiSpies);
|
||||
chai.use(chaiAsPromised);
|
||||
|
||||
const sandbox = chai.spy.sandbox();
|
||||
describe('Bulk', function () {
|
||||
const sandbox = chai.spy.sandbox();
|
||||
|
||||
const bulkAddRoute = new SCBulkAddRoute();
|
||||
const bulkDoneRoute = new SCBulkDoneRoute();
|
||||
const bulkAddRoute = new SCBulkAddRoute();
|
||||
const bulkDoneRoute = new SCBulkDoneRoute();
|
||||
|
||||
const httpClient = new HttpClient();
|
||||
const client = new Client(httpClient, 'http://localhost');
|
||||
const httpClient = new HttpClient();
|
||||
const client = new Client(httpClient, 'http://localhost');
|
||||
|
||||
@suite()
|
||||
export class BulkSpec {
|
||||
@test
|
||||
async add() {
|
||||
afterEach(function () {
|
||||
sandbox.restore();
|
||||
})
|
||||
|
||||
it('should add', async function () {
|
||||
sandbox.on(client, 'invokeRoute', () => {
|
||||
return {};
|
||||
});
|
||||
@@ -82,10 +80,9 @@ export class BulkSpec {
|
||||
},
|
||||
dish,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async addFails() {
|
||||
it('should fail add', async function () {
|
||||
const bulk = new Bulk(SCThingType.Dish, client, {
|
||||
expiration: moment().add(3600, 'seconds').format(),
|
||||
source: 'foo',
|
||||
@@ -108,15 +105,10 @@ export class BulkSpec {
|
||||
uid: 'foo',
|
||||
};
|
||||
|
||||
return bulk.add(message).should.be.rejectedWith(BulkWithMultipleTypesError);
|
||||
}
|
||||
await bulk.add(message).should.be.rejectedWith(BulkWithMultipleTypesError);
|
||||
});
|
||||
|
||||
async after() {
|
||||
sandbox.restore();
|
||||
}
|
||||
|
||||
@test
|
||||
async construct() {
|
||||
it('should construct', function () {
|
||||
expect(() => {
|
||||
return new Bulk(SCThingType.Dish, client, {
|
||||
expiration: moment().add(3600, 'seconds').format(),
|
||||
@@ -126,10 +118,9 @@ export class BulkSpec {
|
||||
uid: 'bar',
|
||||
});
|
||||
}).not.to.throw();
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async done() {
|
||||
it('should done', async function () {
|
||||
sandbox.on(client, 'invokeRoute', () => {
|
||||
return {};
|
||||
});
|
||||
@@ -149,5 +140,5 @@ export class BulkSpec {
|
||||
expect(client.invokeRoute).to.have.been.first.called.with(bulkDoneRoute, {
|
||||
UID: 'bar',
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -28,11 +28,7 @@ import {expect} from 'chai';
|
||||
import chai from 'chai';
|
||||
import chaiAsPromised from 'chai-as-promised';
|
||||
import chaiSpies from 'chai-spies';
|
||||
import {suite, test} from '@testdeck/mocha';
|
||||
import {Client} from '../src/client.js';
|
||||
import {ApiError, OutOfRangeError} from '../src/errors.js';
|
||||
import {HttpClient} from '../src/http-client.js';
|
||||
import {HttpClientResponse} from '../src/http-client-interface.js';
|
||||
import {ApiError, OutOfRangeError, Client, HttpClient, HttpClientResponse} from '../src/index.js';
|
||||
|
||||
chai.should();
|
||||
chai.use(chaiSpies);
|
||||
@@ -84,21 +80,18 @@ async function invokeIndexRouteFails(): Promise<RecursivePartial<HttpClientRespo
|
||||
};
|
||||
}
|
||||
|
||||
@suite()
|
||||
export class ClientSpec {
|
||||
async after() {
|
||||
describe('Client', function () {
|
||||
afterEach(function () {
|
||||
sandbox.restore();
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async construct() {
|
||||
it('should construct', function () {
|
||||
expect(() => {
|
||||
return new Client(httpClient, 'http://localhost');
|
||||
}).not.to.throw();
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async constructWithHeaders() {
|
||||
it('should construct with headers', async function () {
|
||||
sandbox.on(httpClient, 'request', invokeIndexRoute);
|
||||
|
||||
expect(httpClient.request).not.to.have.been.first.called();
|
||||
@@ -115,10 +108,9 @@ export class ClientSpec {
|
||||
method: indexRoute.method,
|
||||
url: new URL('http://localhost' + indexRoute.getUrlPath()),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async getThing() {
|
||||
it('should get thing', async function () {
|
||||
const message: SCMessage = {
|
||||
audiences: ['employees'],
|
||||
categories: ['news'],
|
||||
@@ -174,10 +166,9 @@ export class ClientSpec {
|
||||
method: searchRoute.method,
|
||||
url: new URL('http://localhost' + searchRoute.getUrlPath()),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async getThingFailsByEmptyResponse() {
|
||||
it('should fail getThing by empty response', async function () {
|
||||
sandbox.on(httpClient, 'request', async (): Promise<HttpClientResponse<SCSearchResponse>> => {
|
||||
return {
|
||||
body: {
|
||||
@@ -202,10 +193,9 @@ export class ClientSpec {
|
||||
const client = new Client(httpClient, 'http://localhost');
|
||||
|
||||
return client.getThing('bar').should.be.rejected;
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async getThingFailsByUid() {
|
||||
it('should fail getThing by uid', async function () {
|
||||
const message: SCMessage = {
|
||||
audiences: ['employees'],
|
||||
categories: ['news'],
|
||||
@@ -244,10 +234,9 @@ export class ClientSpec {
|
||||
const client = new Client(httpClient, 'http://localhost');
|
||||
|
||||
return client.getThing('bar').should.be.rejected;
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async handshake() {
|
||||
it('should handshake', async function () {
|
||||
sandbox.on(httpClient, 'request', invokeIndexRoute);
|
||||
|
||||
expect(httpClient.request).not.to.have.been.first.called();
|
||||
@@ -263,10 +252,9 @@ export class ClientSpec {
|
||||
method: indexRoute.method,
|
||||
url: new URL('http://localhost' + indexRoute.getUrlPath()),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async handshakeFails() {
|
||||
it('should fail handshake', async function () {
|
||||
sandbox.on(httpClient, 'request', invokeIndexRoute);
|
||||
|
||||
expect(httpClient.request).not.to.have.been.first.called();
|
||||
@@ -274,10 +262,9 @@ export class ClientSpec {
|
||||
const client = new Client(httpClient, 'http://localhost');
|
||||
|
||||
return client.handshake('bar.bar.dummy').should.be.rejectedWith(ApiError);
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async invokePlugin() {
|
||||
it('should invoke plugin', async function () {
|
||||
sandbox.on(
|
||||
httpClient,
|
||||
'request',
|
||||
@@ -303,13 +290,12 @@ export class ClientSpec {
|
||||
await client.invokePlugin('unsupportedPlugin').should.be.rejectedWith(ApiError, /.*supportedPlugin.*/gim);
|
||||
|
||||
// again with cached feature definitions
|
||||
return client
|
||||
await client
|
||||
.invokePlugin('supportedPlugin')
|
||||
.should.not.be.rejectedWith(ApiError, /.*supportedPlugin.*/gim);
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async invokePluginUnavailable() {
|
||||
it('should invoke unavailable plugin', async function () {
|
||||
sandbox.on(
|
||||
httpClient,
|
||||
'request',
|
||||
@@ -350,10 +336,9 @@ export class ClientSpec {
|
||||
);
|
||||
// again with cached feature definitions
|
||||
return client.invokePlugin('supportedPlugin').should.be.rejectedWith(ApiError, /.*supportedPlugin.*/gim);
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async invokeRoute() {
|
||||
it('should invoke route', async function () {
|
||||
sandbox.on(httpClient, 'request', invokeIndexRoute);
|
||||
|
||||
expect(httpClient.request).not.to.have.been.first.called();
|
||||
@@ -369,10 +354,9 @@ export class ClientSpec {
|
||||
method: indexRoute.method,
|
||||
url: new URL('http://localhost' + indexRoute.getUrlPath()),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async invokeRouteFails() {
|
||||
it('should fail to invoke route', async function () {
|
||||
sandbox.on(httpClient, 'request', invokeIndexRouteFails);
|
||||
|
||||
expect(httpClient.request).not.to.have.been.first.called();
|
||||
@@ -380,10 +364,9 @@ export class ClientSpec {
|
||||
const client = new Client(httpClient, 'http://localhost');
|
||||
|
||||
return client.invokeRoute(indexRoute).should.be.rejectedWith(ApiError);
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async multiSearch() {
|
||||
it('should multi search', async function () {
|
||||
sandbox.on(httpClient, 'request', async (): Promise<HttpClientResponse<SCMultiSearchResponse>> => {
|
||||
return {
|
||||
body: {
|
||||
@@ -430,10 +413,9 @@ export class ClientSpec {
|
||||
method: multiSearchRoute.method,
|
||||
url: new URL('http://localhost' + multiSearchRoute.getUrlPath()),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async multiSearchWithPreflight() {
|
||||
it('should multi search with preflight', async function () {
|
||||
sandbox.on(httpClient, 'request', async (): Promise<HttpClientResponse<SCMultiSearchResponse>> => {
|
||||
return {
|
||||
body: {
|
||||
@@ -488,10 +470,9 @@ export class ClientSpec {
|
||||
method: multiSearchRoute.method,
|
||||
url: new URL('http://localhost' + multiSearchRoute.getUrlPath()),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
nextWindow() {
|
||||
it('should next window', async function () {
|
||||
let searchRequest: SCSearchRequest = {size: 30};
|
||||
const searchResponse: SCSearchResponse = {
|
||||
data: [],
|
||||
@@ -515,10 +496,9 @@ export class ClientSpec {
|
||||
expect(() => {
|
||||
Client.nextWindow(searchRequest, searchResponse);
|
||||
}).to.throw(OutOfRangeError);
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async search() {
|
||||
it('should search', async function () {
|
||||
sandbox.on(httpClient, 'request', async (): Promise<HttpClientResponse<SCSearchResponse>> => {
|
||||
return {
|
||||
body: {
|
||||
@@ -551,10 +531,9 @@ export class ClientSpec {
|
||||
method: searchRoute.method,
|
||||
url: new URL('http://localhost' + searchRoute.getUrlPath()),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async searchNext() {
|
||||
it('should search next', async function () {
|
||||
const searchResponse: SCSearchResponse = {
|
||||
data: [],
|
||||
facets: [],
|
||||
@@ -589,10 +568,9 @@ export class ClientSpec {
|
||||
method: searchRoute.method,
|
||||
url: new URL('http://localhost' + searchRoute.getUrlPath()),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async searchWithPreflight() {
|
||||
it('should search with preflight', async function () {
|
||||
sandbox.on(httpClient, 'request', async (): Promise<HttpClientResponse<SCSearchResponse>> => {
|
||||
return {
|
||||
body: {
|
||||
@@ -633,5 +611,5 @@ export class ClientSpec {
|
||||
method: searchRoute.method,
|
||||
url: new URL('http://localhost' + searchRoute.getUrlPath()),
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable unicorn/no-null */
|
||||
/*
|
||||
* Copyright (C) 2018 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
@@ -12,7 +13,6 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {asyncPool} from '@krlwlfrt/async-pool/lib/async-pool';
|
||||
import {
|
||||
isThing,
|
||||
SCBulkAddResponse,
|
||||
@@ -33,16 +33,12 @@ import {expect} from 'chai';
|
||||
import chaiAsPromised from 'chai-as-promised';
|
||||
import chaiSpies from 'chai-spies';
|
||||
import clone = require('rfdc');
|
||||
import {readdir, readFile} from 'fs';
|
||||
import {suite, test} from '@testdeck/mocha';
|
||||
import moment from 'moment';
|
||||
import {join, resolve} from 'path';
|
||||
import traverse from 'traverse';
|
||||
import {promisify} from 'util';
|
||||
import {ConnectorClient} from '../src/connector-client.js';
|
||||
import {EmptyBulkError, NamespaceNotDefinedError} from '../src/errors.js';
|
||||
import {HttpClient} from '../src/http-client.js';
|
||||
import {HttpClientRequest, HttpClientResponse} from '../src/http-client-interface.js';
|
||||
import {ConnectorClient, EmptyBulkError, NamespaceNotDefinedError, HttpClient, HttpClientRequest, HttpClientResponse} from '../src/index.js';
|
||||
import path from "path";
|
||||
import {fileURLToPath} from "url";
|
||||
import {readdir, readFile} from "fs/promises";
|
||||
|
||||
chai.should();
|
||||
chai.use(chaiSpies);
|
||||
@@ -55,9 +51,6 @@ const bulkDoneRoute = new SCBulkDoneRoute();
|
||||
const bulkRoute = new SCBulkRoute();
|
||||
const thingUpdateRoute = new SCThingUpdateRoute();
|
||||
|
||||
const readdirPromisified = promisify(readdir);
|
||||
const readFilePromisified = promisify(readFile);
|
||||
|
||||
const httpClient = new HttpClient();
|
||||
|
||||
/**
|
||||
@@ -76,14 +69,12 @@ function doesContainThings<T extends SCThingWithoutReferences>(thing: T): boolea
|
||||
}, false);
|
||||
}
|
||||
|
||||
@suite()
|
||||
export class ConnectorClientSpec {
|
||||
async after() {
|
||||
describe('ConnectorClient', function () {
|
||||
afterEach(function () {
|
||||
sandbox.restore();
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async bulk() {
|
||||
it('should bulk', async function () {
|
||||
sandbox.on(httpClient, 'request', async (): Promise<HttpClientResponse<SCBulkResponse>> => {
|
||||
return {
|
||||
body: {
|
||||
@@ -115,10 +106,9 @@ export class ConnectorClientSpec {
|
||||
method: bulkRoute.method,
|
||||
url: new URL('http://localhost' + bulkRoute.getUrlPath()),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async bulkWithoutTimeout() {
|
||||
it('should bulk without timeout', async function () {
|
||||
sandbox.on(httpClient, 'request', async (): Promise<HttpClientResponse<SCBulkResponse>> => {
|
||||
return {
|
||||
body: {
|
||||
@@ -150,10 +140,9 @@ export class ConnectorClientSpec {
|
||||
method: bulkRoute.method,
|
||||
url: new URL('http://localhost' + bulkRoute.getUrlPath()),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async index() {
|
||||
it('should index', async function () {
|
||||
const messages: SCMessage[] = [
|
||||
{
|
||||
audiences: ['employees'],
|
||||
@@ -240,16 +229,14 @@ export class ConnectorClientSpec {
|
||||
method: bulkRoute.method,
|
||||
url: new URL('http://localhost' + bulkRoute.getUrlPath()),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async indexFails() {
|
||||
it('should fail to index', async function () {
|
||||
const connectorClient = new ConnectorClient(httpClient, 'http://localhost');
|
||||
return connectorClient.index([]).should.be.rejectedWith(EmptyBulkError);
|
||||
}
|
||||
await connectorClient.index([]).should.be.rejectedWith(EmptyBulkError);
|
||||
});
|
||||
|
||||
@test
|
||||
async indexWithoutSource() {
|
||||
it('should index without source', async function () {
|
||||
const messages: SCMessage[] = [
|
||||
{
|
||||
audiences: ['employees'],
|
||||
@@ -336,28 +323,25 @@ export class ConnectorClientSpec {
|
||||
method: bulkRoute.method,
|
||||
url: new URL('http://localhost' + bulkRoute.getUrlPath()),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
makeUuid() {
|
||||
it('should make uuid', async function () {
|
||||
const uuid = ConnectorClient.makeUUID('foo', 'b-tu');
|
||||
|
||||
expect(uuid).to.be.equal('abad271e-d9e9-5802-b7bc-96d8a647b451');
|
||||
expect(ConnectorClient.makeUUID('bar', 'b-tu')).not.to.be.equal(uuid);
|
||||
expect(ConnectorClient.makeUUID('foo', 'f-u')).not.to.be.equal(uuid);
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
makeUuidFails() {
|
||||
it('should fail making a uuid', async function (){
|
||||
expect(() => {
|
||||
ConnectorClient.makeUUID('foo', 'b-u');
|
||||
}).to.throw(NamespaceNotDefinedError);
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async removeReferences() {
|
||||
const pathToTestFiles = resolve(
|
||||
__dirname,
|
||||
it('should remove references', async function () {
|
||||
const pathToTestFiles = path.resolve(
|
||||
path.dirname(fileURLToPath(import.meta.url)),
|
||||
'..',
|
||||
'node_modules',
|
||||
'@openstapps',
|
||||
@@ -367,14 +351,14 @@ export class ConnectorClientSpec {
|
||||
'indexable',
|
||||
);
|
||||
|
||||
const testFiles = await readdirPromisified(pathToTestFiles);
|
||||
const testFiles = await readdir(pathToTestFiles);
|
||||
|
||||
const testInstances = await asyncPool(5, testFiles, async testFile => {
|
||||
const buffer = await readFilePromisified(join(pathToTestFiles, testFile));
|
||||
const testInstances = await Promise.all(testFiles.map(async testFile => {
|
||||
const buffer = await readFile(path.join(pathToTestFiles, testFile));
|
||||
const content = JSON.parse(buffer.toString());
|
||||
|
||||
return content.instance;
|
||||
});
|
||||
}));
|
||||
|
||||
for (const testInstance of testInstances) {
|
||||
const checkInstance = clone()(testInstance);
|
||||
@@ -384,6 +368,7 @@ export class ConnectorClientSpec {
|
||||
false,
|
||||
JSON.stringify([testInstance, testInstanceWithoutReferences], null, 2),
|
||||
);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
expect((testInstanceWithoutReferences as any).origin).to.be.equal(
|
||||
undefined,
|
||||
JSON.stringify([testInstance, testInstanceWithoutReferences], null, 2),
|
||||
@@ -393,10 +378,9 @@ export class ConnectorClientSpec {
|
||||
'Removing the references of a thing could have side effects because no deep copy is used',
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async removeUndefinedProperties() {
|
||||
it('should remove undefined properties', async function () {
|
||||
const objectWithUndefinedProperties = {
|
||||
value: 'foo',
|
||||
novalue: undefined,
|
||||
@@ -417,10 +401,9 @@ export class ConnectorClientSpec {
|
||||
objectWithoutUndefinedProperties,
|
||||
JSON.stringify([objectWithUndefinedProperties, objectWithoutUndefinedProperties], null, 2),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async update() {
|
||||
it('should update', async function () {
|
||||
const message: SCMessage = {
|
||||
audiences: ['employees'],
|
||||
categories: ['news'],
|
||||
@@ -462,5 +445,5 @@ export class ConnectorClientSpec {
|
||||
}),
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -27,12 +27,9 @@ import {
|
||||
import chai from 'chai';
|
||||
import chaiAsPromised from 'chai-as-promised';
|
||||
import chaiSpies from 'chai-spies';
|
||||
import {suite, test} from '@testdeck/mocha';
|
||||
import moment from 'moment';
|
||||
import {copy} from '../src/copy.js';
|
||||
import {ApiError} from '../src/errors.js';
|
||||
import {HttpClient, RequestOptions, Response} from '../src/http-client.js';
|
||||
import {RecursivePartial} from './client.spec';
|
||||
import {copy, ApiError, HttpClient, RequestOptions, Response} from '../src/index.js';
|
||||
import {RecursivePartial} from './client.spec.js';
|
||||
|
||||
chai.should();
|
||||
chai.use(chaiSpies);
|
||||
@@ -47,14 +44,12 @@ const searchRoute = new SCSearchRoute();
|
||||
|
||||
const httpClient = new HttpClient();
|
||||
|
||||
@suite()
|
||||
export class CopySpec {
|
||||
async after() {
|
||||
describe('Copy', function () {
|
||||
afterEach(function () {
|
||||
sandbox.restore();
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async copy() {
|
||||
it('should copy', async function () {
|
||||
type responses = Response<SCBulkAddResponse | SCBulkDoneResponse | SCBulkResponse | SCSearchResponse>;
|
||||
|
||||
sandbox.on(
|
||||
@@ -133,10 +128,9 @@ export class CopySpec {
|
||||
type: SCThingType.Dish,
|
||||
version: 'foo.bar.foobar',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async copyShouldFail() {
|
||||
it('should fail to copy', async function () {
|
||||
type responses = Response<SCBulkAddResponse | SCBulkDoneResponse | SCBulkResponse | SCSearchResponse>;
|
||||
|
||||
sandbox.on(
|
||||
@@ -206,7 +200,7 @@ export class CopySpec {
|
||||
},
|
||||
);
|
||||
|
||||
return copy(httpClient, {
|
||||
await copy(httpClient, {
|
||||
batchSize: 5,
|
||||
from: 'http://foo.bar',
|
||||
source: 'stapps-copy',
|
||||
@@ -214,5 +208,5 @@ export class CopySpec {
|
||||
type: SCThingType.Dish,
|
||||
version: 'foo.bar.foobar',
|
||||
}).should.be.rejectedWith(ApiError);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,9 +12,7 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// tslint:disable-next-line: max-line-length
|
||||
// tslint:disable: completed-docs no-implicit-dependencies prefer-function-over-method newline-per-chained-call member-ordering
|
||||
// eslint-disable-next-line unicorn/prevent-abbreviations
|
||||
import {
|
||||
SCBulkAddResponse,
|
||||
SCBulkAddRoute,
|
||||
@@ -32,12 +30,12 @@ import chaiSpies from 'chai-spies';
|
||||
import clone = require('rfdc');
|
||||
import {existsSync, mkdirSync, rmdirSync, unlinkSync} from 'fs';
|
||||
import {createFileSync} from 'fs-extra';
|
||||
import {suite, test} from '@testdeck/mocha';
|
||||
import {join} from 'path';
|
||||
import {e2eRun, getItemsFromSamples} from '../src/e2e.js';
|
||||
import {ApiError} from '../src/errors.js';
|
||||
import {HttpClient, RequestOptions, Response} from '../src/http-client.js';
|
||||
import {RecursivePartial} from './client.spec';
|
||||
// eslint-disable-next-line unicorn/prevent-abbreviations
|
||||
import {e2eRun, getItemsFromSamples, ApiError, HttpClient, RequestOptions, Response} from '../src/index.js';
|
||||
import {RecursivePartial} from './client.spec.js';
|
||||
import {expect} from "chai";
|
||||
import path from "path";
|
||||
import {fileURLToPath} from "url";
|
||||
|
||||
chai.should();
|
||||
chai.use(chaiSpies);
|
||||
@@ -55,26 +53,21 @@ const httpClient = new HttpClient();
|
||||
|
||||
const storedThings: Map<string, SCThings> = new Map();
|
||||
|
||||
@suite
|
||||
export class E2EConnectorSpec {
|
||||
async after() {
|
||||
describe('e2e Connector', function () {
|
||||
afterEach(function () {
|
||||
sandbox.restore();
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async getCoreTestSamples() {
|
||||
it('should get core test samples', async function () {
|
||||
const items = await getItemsFromSamples('./node_modules/@openstapps/core/test/resources');
|
||||
// tslint:disable-next-line: no-unused-expression
|
||||
chai.expect(items).to.not.be.empty;
|
||||
}
|
||||
expect(items).to.not.be.empty;
|
||||
});
|
||||
|
||||
@test
|
||||
async getCoreTestSamplesShouldFail() {
|
||||
await chai.expect(getItemsFromSamples('./nonexistantdirectory')).to.be.rejectedWith(Error);
|
||||
}
|
||||
it('should fail to get core test samples', async function () {
|
||||
await chai.expect(getItemsFromSamples('./non-existent-directory')).to.be.rejectedWith(Error);
|
||||
});
|
||||
|
||||
@test
|
||||
async e2eRunSimulation() {
|
||||
it('should run e2e simulation', async function () {
|
||||
type responses = Response<SCBulkAddResponse | SCBulkDoneResponse | SCBulkResponse | SCSearchResponse>;
|
||||
|
||||
let failOnCompare = false;
|
||||
@@ -167,10 +160,9 @@ export class E2EConnectorSpec {
|
||||
to: 'http://localhost',
|
||||
samplesLocation: './node_modules/@openstapps/core/test/resources',
|
||||
}).should.be.rejectedWith('Unexpected difference');
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async indexShouldFail() {
|
||||
it('should fail to index', async function () {
|
||||
type responses = Response<SCBulkAddResponse | SCBulkDoneResponse | SCBulkResponse>;
|
||||
|
||||
sandbox.on(httpClient, 'request', async (): Promise<RecursivePartial<responses>> => {
|
||||
@@ -185,33 +177,31 @@ export class E2EConnectorSpec {
|
||||
to: 'http://localhost',
|
||||
samplesLocation: './node_modules/@openstapps/core/test/resources',
|
||||
}).should.be.rejectedWith(ApiError);
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async indexShouldFailDirectoryWithoutData() {
|
||||
const emptyDirPath = join(__dirname, 'emptyDir');
|
||||
if (!existsSync(emptyDirPath)) {
|
||||
mkdirSync(emptyDirPath);
|
||||
it('should fail to index directory without data', async function () {
|
||||
const emptyDirectoryPath = path.join(path.dirname(fileURLToPath(import.meta.url)), 'emptyDir');
|
||||
if (!existsSync(emptyDirectoryPath)) {
|
||||
mkdirSync(emptyDirectoryPath);
|
||||
}
|
||||
await e2eRun(httpClient, {to: 'http://localhost', samplesLocation: emptyDirPath}).should.be.rejectedWith(
|
||||
await e2eRun(httpClient, {to: 'http://localhost', samplesLocation: emptyDirectoryPath}).should.be.rejectedWith(
|
||||
'Could not index samples. None were retrieved from the file system.',
|
||||
);
|
||||
rmdirSync(emptyDirPath);
|
||||
}
|
||||
rmdirSync(emptyDirectoryPath);
|
||||
});
|
||||
|
||||
@test
|
||||
async indexShouldFailDirectoryWithoutJsonData() {
|
||||
const somewhatFilledDirPath = join(__dirname, 'somewhatFilledDir');
|
||||
if (!existsSync(somewhatFilledDirPath)) {
|
||||
mkdirSync(somewhatFilledDirPath);
|
||||
it('should fail to index directory without json data', async function () {
|
||||
const somewhatFilledDirectoryPath = path.join(path.dirname(fileURLToPath(import.meta.url)), 'somewhatFilledDir');
|
||||
if (!existsSync(somewhatFilledDirectoryPath)) {
|
||||
mkdirSync(somewhatFilledDirectoryPath);
|
||||
}
|
||||
const nonJsonFile = join(somewhatFilledDirPath, 'nonjson.txt');
|
||||
const nonJsonFile = path.join(somewhatFilledDirectoryPath, 'nonjson.txt');
|
||||
createFileSync(nonJsonFile);
|
||||
await e2eRun(httpClient, {
|
||||
to: 'http://localhost',
|
||||
samplesLocation: somewhatFilledDirPath,
|
||||
samplesLocation: somewhatFilledDirectoryPath,
|
||||
}).should.be.rejectedWith('Could not index samples. None were retrieved from the file system.');
|
||||
unlinkSync(nonJsonFile);
|
||||
rmdirSync(somewhatFilledDirPath);
|
||||
}
|
||||
}
|
||||
rmdirSync(somewhatFilledDirectoryPath);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,8 +16,7 @@ import chai from 'chai';
|
||||
import {expect} from 'chai';
|
||||
import chaiAsPromised from 'chai-as-promised';
|
||||
import chaiSpies from 'chai-spies';
|
||||
import {suite, test} from '@testdeck/mocha';
|
||||
import {ApiError} from '../src/errors.js';
|
||||
import {ApiError} from '../src/index.js';
|
||||
|
||||
chai.should();
|
||||
chai.use(chaiSpies);
|
||||
@@ -25,36 +24,32 @@ chai.use(chaiAsPromised);
|
||||
|
||||
const sandbox = chai.spy.sandbox();
|
||||
|
||||
@suite()
|
||||
export class ErrorsSpec {
|
||||
async after() {
|
||||
describe('Errors', function () {
|
||||
afterEach(function () {
|
||||
sandbox.restore();
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async shouldAddAdditionalData() {
|
||||
it('should add additional data', function () {
|
||||
const error = new ApiError({
|
||||
additionalData: 'Lorem ipsum',
|
||||
});
|
||||
|
||||
expect(error.toString()).to.contain('Lorem ipsum');
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async shouldAddRemoteStackTrace() {
|
||||
it('should add remote stack-trace', async function () {
|
||||
const error = new ApiError({
|
||||
stack: 'Lorem ipsum',
|
||||
});
|
||||
|
||||
expect(error.toString()).to.contain('Lorem ipsum');
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async shouldSetName() {
|
||||
it('should set name', async function () {
|
||||
const error = new ApiError({
|
||||
name: 'Foo',
|
||||
});
|
||||
|
||||
expect(error.name).to.be.equal('Foo');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,27 +13,23 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {expect} from 'chai';
|
||||
import {suite, test} from '@testdeck/mocha';
|
||||
import nock from 'nock';
|
||||
import {HttpClient} from '../src/http-client.js';
|
||||
import {HttpClient} from '../src/index.js';
|
||||
|
||||
// TODO: use after each to clean up the nock (then there is no need for numerated resource links)
|
||||
|
||||
@suite()
|
||||
export class HttpClientSpec {
|
||||
@test
|
||||
async construct() {
|
||||
describe('HttpClient', function () {
|
||||
afterEach(function () {
|
||||
nock.cleanAll();
|
||||
})
|
||||
|
||||
it('should construct', function () {
|
||||
expect(() => {
|
||||
return new HttpClient();
|
||||
}).not.to.throw();
|
||||
}
|
||||
});
|
||||
|
||||
async after() {
|
||||
nock.cleanAll();
|
||||
}
|
||||
|
||||
@test
|
||||
async request() {
|
||||
it('should request', async function () {
|
||||
const client = new HttpClient();
|
||||
|
||||
nock('http://www.example.com').get('/resource').reply(200, 'foo');
|
||||
@@ -43,10 +39,9 @@ export class HttpClientSpec {
|
||||
});
|
||||
|
||||
expect(response.body).to.be.equal('foo');
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async requestWithBody() {
|
||||
it('should request with body', async function () {
|
||||
const client = new HttpClient();
|
||||
|
||||
nock('http://www.example.com').get('/resource').reply(200, 'foo');
|
||||
@@ -56,12 +51,11 @@ export class HttpClientSpec {
|
||||
});
|
||||
|
||||
expect(response.body).to.be.equal('foo');
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async requestWithError() {
|
||||
it('should request with error', async function () {
|
||||
const client = new HttpClient();
|
||||
let caughtErr;
|
||||
let caughtError;
|
||||
|
||||
nock('http://www.example.com').get('/resource').replyWithError('foo');
|
||||
|
||||
@@ -72,15 +66,14 @@ export class HttpClientSpec {
|
||||
},
|
||||
url: new URL('http://www.example.com/resource'),
|
||||
});
|
||||
} catch (err) {
|
||||
caughtErr = err;
|
||||
} catch (error) {
|
||||
caughtError = error;
|
||||
}
|
||||
|
||||
expect(caughtErr).not.to.be.undefined;
|
||||
}
|
||||
expect(caughtError).not.to.be.undefined;
|
||||
});
|
||||
|
||||
@test
|
||||
async requestWithHeaders() {
|
||||
it('should request with headers', async function () {
|
||||
const client = new HttpClient();
|
||||
|
||||
nock('http://www.example.com').get('/resource').reply(200, 'foo');
|
||||
@@ -93,10 +86,9 @@ export class HttpClientSpec {
|
||||
});
|
||||
|
||||
expect(response.body).to.be.equal('foo');
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async requestWithMethodGet() {
|
||||
it('should request with method GET', async function () {
|
||||
const client = new HttpClient();
|
||||
|
||||
nock('http://www.example.com').get('/resource').reply(200, 'foo');
|
||||
@@ -107,10 +99,9 @@ export class HttpClientSpec {
|
||||
});
|
||||
|
||||
expect(response.body).to.be.equal('foo');
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async requestWithMethodPost() {
|
||||
it('should request with method POST', async function () {
|
||||
const client = new HttpClient();
|
||||
|
||||
nock('http://www.example.com').post('/resource').reply(200, 'foo');
|
||||
@@ -121,5 +112,5 @@ export class HttpClientSpec {
|
||||
});
|
||||
|
||||
expect(response.body).to.be.equal('foo');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,10 +16,7 @@ import {SCPluginRegisterRequest, SCPluginRegisterResponse, SCPluginRegisterRoute
|
||||
import chai from 'chai';
|
||||
import {expect} from 'chai';
|
||||
import chaiSpies from 'chai-spies';
|
||||
import {suite, test, timeout} from '@testdeck/mocha';
|
||||
import {HttpClient} from '../src/http-client.js';
|
||||
import {HttpClientResponse} from '../src/http-client-interface.js';
|
||||
import {PluginClient} from '../src/plugin-client.js';
|
||||
import {HttpClient, HttpClientResponse, PluginClient} from '../src/index.js';
|
||||
import {TestPlugin} from './plugin-resources/test-plugin.js';
|
||||
|
||||
chai.use(chaiSpies);
|
||||
@@ -27,21 +24,16 @@ chai.use(chaiSpies);
|
||||
const sandbox = chai.spy.sandbox();
|
||||
|
||||
const httpClient = new HttpClient();
|
||||
|
||||
const pluginRegisterRoute = new SCPluginRegisterRoute();
|
||||
|
||||
const pluginClient = new PluginClient(httpClient, 'http://localhost');
|
||||
|
||||
@suite(timeout(10000))
|
||||
export class PluginClientSpec {
|
||||
static plugin: TestPlugin;
|
||||
describe('PluginClient', function () {
|
||||
this.timeout(10_000);
|
||||
|
||||
static async after() {
|
||||
await this.plugin.close();
|
||||
}
|
||||
let plugin: TestPlugin;
|
||||
|
||||
static async before() {
|
||||
this.plugin = new TestPlugin(
|
||||
beforeEach(async function () {
|
||||
plugin = new TestPlugin(
|
||||
4000,
|
||||
'',
|
||||
'',
|
||||
@@ -51,19 +43,19 @@ export class PluginClientSpec {
|
||||
getSchema: () => {
|
||||
/***/
|
||||
},
|
||||
} as any,
|
||||
} as never,
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
async after() {
|
||||
afterEach(async function () {
|
||||
await plugin.close();
|
||||
sandbox.restore();
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async registerPlugin() {
|
||||
it('should register the plugin', async function () {
|
||||
sandbox.on(httpClient, 'request', async (): Promise<HttpClientResponse<SCPluginRegisterResponse>> => {
|
||||
return {
|
||||
body: {
|
||||
@@ -76,16 +68,16 @@ export class PluginClientSpec {
|
||||
|
||||
expect(httpClient.request).not.to.have.been.called();
|
||||
|
||||
await pluginClient.registerPlugin(PluginClientSpec.plugin);
|
||||
await pluginClient.registerPlugin(plugin);
|
||||
|
||||
const request: SCPluginRegisterRequest = {
|
||||
action: 'add',
|
||||
plugin: {
|
||||
address: PluginClientSpec.plugin.fullUrl,
|
||||
name: PluginClientSpec.plugin.name,
|
||||
requestSchema: PluginClientSpec.plugin.requestSchema,
|
||||
responseSchema: PluginClientSpec.plugin.responseSchema,
|
||||
route: PluginClientSpec.plugin.route,
|
||||
address: plugin.fullUrl,
|
||||
name: plugin.name,
|
||||
requestSchema: plugin.requestSchema,
|
||||
responseSchema: plugin.responseSchema,
|
||||
route: plugin.route,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -97,10 +89,9 @@ export class PluginClientSpec {
|
||||
method: pluginRegisterRoute.method,
|
||||
url: new URL(`http://localhost${pluginRegisterRoute.getUrlPath()}`),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async unregisterPlugin() {
|
||||
it('should unregister the plugin', async function () {
|
||||
sandbox.on(httpClient, 'request', async (): Promise<HttpClientResponse<SCPluginRegisterResponse>> => {
|
||||
return {
|
||||
body: {
|
||||
@@ -113,11 +104,11 @@ export class PluginClientSpec {
|
||||
|
||||
expect(httpClient.request).not.to.have.been.called();
|
||||
|
||||
await pluginClient.unregisterPlugin(PluginClientSpec.plugin);
|
||||
await pluginClient.unregisterPlugin(plugin);
|
||||
|
||||
const request: SCPluginRegisterRequest = {
|
||||
action: 'remove',
|
||||
route: PluginClientSpec.plugin.route,
|
||||
route: plugin.route,
|
||||
};
|
||||
|
||||
expect(httpClient.request).to.have.been.first.called.with({
|
||||
@@ -128,5 +119,5 @@ export class PluginClientSpec {
|
||||
method: pluginRegisterRoute.method,
|
||||
url: new URL(`http://localhost${pluginRegisterRoute.getUrlPath()}`),
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,36 +13,35 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {Converter} from '@openstapps/core-tools/lib/schema';
|
||||
import {Converter} from '@openstapps/core-tools';
|
||||
import chai from 'chai';
|
||||
import {expect} from 'chai';
|
||||
import chaiSpies from 'chai-spies';
|
||||
import {readFileSync} from 'fs';
|
||||
import {suite, test, timeout} from '@testdeck/mocha';
|
||||
import {resolve} from 'path';
|
||||
import {HttpClient} from '../src/http-client.js';
|
||||
import {HttpClient} from '../src/index.js';
|
||||
import {TestPlugin} from './plugin-resources/test-plugin.js';
|
||||
import path from "path";
|
||||
import {readFile} from "fs/promises";
|
||||
import {fileURLToPath} from "url";
|
||||
|
||||
chai.use(chaiSpies);
|
||||
|
||||
process.on('unhandledRejection', err => {
|
||||
throw err;
|
||||
process.on('unhandledRejection', error => {
|
||||
throw error;
|
||||
});
|
||||
|
||||
const sandbox = chai.spy.sandbox();
|
||||
|
||||
const httpClient = new HttpClient();
|
||||
|
||||
@suite(timeout(20000))
|
||||
export class PluginSpec {
|
||||
static testPlugin: TestPlugin;
|
||||
const dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
static async after() {
|
||||
PluginSpec.testPlugin.close();
|
||||
}
|
||||
describe('Plugin', function () {
|
||||
this.timeout(20_000);
|
||||
|
||||
static async before() {
|
||||
PluginSpec.testPlugin = new TestPlugin(
|
||||
let testPlugin: TestPlugin;
|
||||
|
||||
beforeEach(function () {
|
||||
testPlugin = new TestPlugin(
|
||||
4000,
|
||||
'',
|
||||
'',
|
||||
@@ -52,22 +51,22 @@ export class PluginSpec {
|
||||
getSchema: () => {
|
||||
/***/
|
||||
},
|
||||
} as any,
|
||||
} as never,
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
);
|
||||
}
|
||||
})
|
||||
|
||||
async after() {
|
||||
afterEach(async function () {
|
||||
await testPlugin.close();
|
||||
sandbox.restore();
|
||||
}
|
||||
})
|
||||
|
||||
@test
|
||||
async construct() {
|
||||
it('should construct', async function () {
|
||||
const converter = new Converter(
|
||||
__dirname,
|
||||
resolve(__dirname, 'plugin-resources', 'test-plugin-response.ts'),
|
||||
dirname,
|
||||
path.resolve(dirname, 'plugin-resources', 'test-plugin-response.ts'),
|
||||
);
|
||||
|
||||
sandbox.on(converter, 'getSchema', schemaName => {
|
||||
@@ -80,20 +79,19 @@ export class PluginSpec {
|
||||
'http://B',
|
||||
'/C', // this doesn't matter for our tests, it's only something that affects the backend
|
||||
'http://D',
|
||||
// @ts-ignore fake converter is not a converter
|
||||
converter,
|
||||
'PluginTestRequest',
|
||||
'PluginTestResponse',
|
||||
JSON.parse(readFileSync(resolve(__dirname, '..', 'package.json')).toString()).version,
|
||||
JSON.parse(await readFile(path.resolve(dirname, '..', 'package.json'), 'utf8')).version,
|
||||
);
|
||||
expect(constructTestPlugin.port).to.be.equal(4001);
|
||||
expect(constructTestPlugin.name).to.be.equal('A');
|
||||
expect(constructTestPlugin.url).to.be.equal('http://B');
|
||||
expect(constructTestPlugin.route).to.be.equal('/C');
|
||||
// @ts-ignore backendUrl is protected
|
||||
// @ts-expect-error private property
|
||||
expect(constructTestPlugin.backendUrl).to.be.equal('http://D');
|
||||
// schemas are already covered, together with the directory and version
|
||||
// @ts-ignore active is private
|
||||
// @ts-expect-error private property
|
||||
expect(constructTestPlugin.active).to.be.equal(false);
|
||||
expect(constructTestPlugin.requestSchema.$id).to.be.equal('PluginTestRequest');
|
||||
expect(constructTestPlugin.responseSchema.$id).to.be.equal('PluginTestResponse');
|
||||
@@ -103,15 +101,14 @@ export class PluginSpec {
|
||||
url: new URL('http://localhost:4001'),
|
||||
});
|
||||
// onRouteInvoke is a protected method, but we need to access it from the outside to test it
|
||||
// @ts-ignore
|
||||
// @ts-expect-error protected method
|
||||
expect(constructTestPlugin.onRouteInvoke).not.to.have.been.called();
|
||||
|
||||
await constructTestPlugin.close();
|
||||
sandbox.restore(constructTestPlugin, 'onRouteInvoke');
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async fullUrl() {
|
||||
it('should have full url', async function () {
|
||||
const constructTestPlugin = new TestPlugin(
|
||||
4001,
|
||||
'',
|
||||
@@ -122,37 +119,35 @@ export class PluginSpec {
|
||||
getSchema: () => {
|
||||
/***/
|
||||
},
|
||||
} as any,
|
||||
} as never,
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
);
|
||||
expect(constructTestPlugin.fullUrl).to.be.equal('http://B:4001');
|
||||
await constructTestPlugin.close();
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async start() {
|
||||
PluginSpec.testPlugin.start();
|
||||
it('should start', async function () {
|
||||
testPlugin.start();
|
||||
|
||||
sandbox.on(PluginSpec.testPlugin, 'onRouteInvoke');
|
||||
sandbox.on(testPlugin, 'onRouteInvoke');
|
||||
|
||||
await httpClient.request({
|
||||
url: new URL('http://localhost:4000'),
|
||||
});
|
||||
|
||||
// onRouteInvoke is a protected method, but we need to access it from the outside to test it
|
||||
// @ts-ignore
|
||||
expect(PluginSpec.testPlugin.onRouteInvoke).to.have.been.called();
|
||||
}
|
||||
// @ts-expect-error protected method
|
||||
expect(testPlugin.onRouteInvoke).to.have.been.called();
|
||||
});
|
||||
|
||||
@test
|
||||
async stop() {
|
||||
it('should stop', async function () {
|
||||
// simulate a normal use case by first starting the plugin and then stopping it
|
||||
PluginSpec.testPlugin.start();
|
||||
PluginSpec.testPlugin.stop();
|
||||
testPlugin.start();
|
||||
testPlugin.stop();
|
||||
|
||||
sandbox.on(PluginSpec.testPlugin, 'onRouteInvoke');
|
||||
sandbox.on(testPlugin, 'onRouteInvoke');
|
||||
|
||||
const response = await httpClient.request({
|
||||
url: new URL('http://localhost:4000'),
|
||||
@@ -160,7 +155,7 @@ export class PluginSpec {
|
||||
|
||||
await expect(response.statusCode).to.be.equal(404);
|
||||
// onRouteInvoke is a protected method, but we need to access it from the outside to test it
|
||||
// @ts-ignore
|
||||
expect(PluginSpec.testPlugin.onRouteInvoke).not.to.have.been.called();
|
||||
}
|
||||
}
|
||||
// @ts-expect-error protected method
|
||||
expect(testPlugin.onRouteInvoke).not.to.have.been.called();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,20 +6,20 @@
|
||||
"main": "lib/index.js",
|
||||
"scripts": {
|
||||
"build": "tsup --dts",
|
||||
"format": "prettier .",
|
||||
"format:fix": "prettier --write .",
|
||||
"format": "prettier . --ignore-path ../../.gitignore",
|
||||
"format:fix": "prettier --write . --ignore-path ../../.gitignore",
|
||||
"lint": "eslint --ext .ts src/",
|
||||
"lint:fix": "eslint --fix --ext .ts src/",
|
||||
"test": "nyc mocha 'test/**/*.spec.ts'"
|
||||
"test": "c8 mocha"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@openstapps/eslint-config": "workspace:*",
|
||||
"@openstapps/nyc-config": "workspace:*",
|
||||
"@openstapps/prettier-config": "workspace:*",
|
||||
"@openstapps/tsconfig": "workspace:*",
|
||||
"@types/node": "18.15.3",
|
||||
"@types/chai": "4.3.4",
|
||||
"@types/mocha": "10.0.1",
|
||||
"@types/node": "18.15.3",
|
||||
"c8": "7.13.0",
|
||||
"chai": "4.3.7",
|
||||
"mocha": "10.2.0",
|
||||
"ts-node": "10.9.1",
|
||||
@@ -41,8 +41,5 @@
|
||||
"@openstapps"
|
||||
]
|
||||
},
|
||||
"nyc": {
|
||||
"extends": "@openstapps/nyc-config"
|
||||
},
|
||||
"exports": "./lib/index.js"
|
||||
}
|
||||
|
||||
@@ -12,8 +12,7 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {chunk} from '../src/chunk.js';
|
||||
import {chunk} from '../src/index.js';
|
||||
import {expect} from 'chai';
|
||||
|
||||
describe('chunk', function () {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {differenceBy} from '../src/difference.js';
|
||||
import {differenceBy} from '../src/index.js';
|
||||
import {expect} from 'chai';
|
||||
|
||||
describe('differenceBy', function () {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {get} from '../src/get.js';
|
||||
import {get} from '../src/index.js';
|
||||
import {expect} from 'chai';
|
||||
|
||||
describe('get', function () {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {groupBy, groupByStable, groupByProperty} from '../src/group-by.js';
|
||||
import {groupBy, groupByStable, groupByProperty} from '../src/index.js';
|
||||
import {expect} from 'chai';
|
||||
|
||||
describe('groupBy', () => {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {keyBy} from '../src/key-by.js';
|
||||
import {keyBy} from '../src/index.js';
|
||||
import {expect} from 'chai';
|
||||
|
||||
describe('keyBy', function () {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {mapValues} from '../src/map-values.js';
|
||||
import {mapValues} from '../src/index.js';
|
||||
import {expect} from 'chai';
|
||||
|
||||
describe('map-values', () => {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {minBy} from '../src/min.js';
|
||||
import {minBy} from '../src/index.js';
|
||||
import {expect} from 'chai';
|
||||
|
||||
describe('minBy', function () {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {omit} from '../src/omit.js';
|
||||
import {omit} from '../src/index.js';
|
||||
import {expect} from 'chai';
|
||||
|
||||
describe('omit', function () {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {partition} from '../src/partition.js';
|
||||
import {partition} from '../src/index.js';
|
||||
import {expect} from 'chai';
|
||||
|
||||
describe('partition', function () {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {pick} from '../src/pick.js';
|
||||
import {pick} from '../src/index.js';
|
||||
import {expect} from 'chai';
|
||||
|
||||
describe('pick', function () {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {shuffle} from '../src/shuffle.js';
|
||||
import {shuffle} from '../src/index.js';
|
||||
import {expect} from 'chai';
|
||||
|
||||
describe('shuffle', function () {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {stringSort, stringSortBy} from '../src/string-sort.js';
|
||||
import {stringSort, stringSortBy} from '../src/index.js';
|
||||
import {expect} from 'chai';
|
||||
|
||||
describe('stringSort', () => {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {expect} from 'chai';
|
||||
import {sum, sumBy} from '../src/sum.js';
|
||||
import {sum, sumBy} from '../src/index.js';
|
||||
|
||||
describe('sum', () => {
|
||||
it('should return the sum of all elements in the collection', () => {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {expect} from 'chai';
|
||||
import {Tree, treeGroupBy} from '../src/tree-group.js';
|
||||
import {Tree, treeGroupBy} from '../src/index.js';
|
||||
|
||||
interface TestItem {
|
||||
id: number;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {expect} from 'chai';
|
||||
import {uniqBy} from '../src/uniq.js';
|
||||
import {uniqBy} from '../src/index.js';
|
||||
|
||||
describe('uniq', function () {
|
||||
it('should return an array with unique values', function () {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {expect} from 'chai';
|
||||
import {zip} from '../src/zip.js';
|
||||
import {zip} from '../src/index.js';
|
||||
|
||||
describe('zip', function () {
|
||||
it('should zip arrays together', function () {
|
||||
|
||||
@@ -46,7 +46,6 @@ Inside of a script in `package.json` or if the npm package is installed globally
|
||||
openstapps-core-tools schema src/core lib/schema
|
||||
```
|
||||
|
||||
|
||||
## How to use the validator?
|
||||
|
||||
### Using the validator programatically
|
||||
|
||||
@@ -27,26 +27,25 @@
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsup --dts",
|
||||
"format": "prettier .",
|
||||
"format:fix": "prettier --write .",
|
||||
"format": "prettier . --ignore-path ../../.gitignore",
|
||||
"format:fix": "prettier --write . --ignore-path ../../.gitignore",
|
||||
"lint": "eslint --ext .ts src/",
|
||||
"lint:fix": "eslint --fix --ext .ts src/",
|
||||
"plantuml-restart": "docker restart plantuml-server",
|
||||
"plantuml-start": "docker run --name plantuml-server -d -p 8080:8080 registry.gitlab.com/openstapps/core-tools:latest",
|
||||
"plantuml-stop": "docker stop plantuml-server",
|
||||
"test": "nyc mocha 'test/**/*.spec.ts'"
|
||||
"test": "c8 mocha"
|
||||
},
|
||||
"dependencies": {
|
||||
"@openstapps/collection-utils": "workspace:*",
|
||||
"@openstapps/logger": "workspace:*",
|
||||
"@openstapps/easy-ast": "workspace:*",
|
||||
"@openstapps/logger": "workspace:*",
|
||||
"ajv": "8.12.0",
|
||||
"re2": "1.18.0",
|
||||
"better-ajv-errors": "1.2.0",
|
||||
"chai": "4.3.7",
|
||||
"commander": "10.0.0",
|
||||
"deepmerge": "4.3.1",
|
||||
"del": "6.1.1",
|
||||
"eslint": "8.33.0",
|
||||
"flatted": "3.2.7",
|
||||
"fs-extra": "10.1.0",
|
||||
"glob": "10.2.1",
|
||||
@@ -56,18 +55,14 @@
|
||||
"mustache": "4.2.0",
|
||||
"openapi-types": "12.1.0",
|
||||
"plantuml-encoder": "1.4.0",
|
||||
"re2": "1.18.0",
|
||||
"toposort": "2.0.2",
|
||||
"ts-json-schema-generator": "1.2.0",
|
||||
"ts-node": "10.9.1",
|
||||
"typescript": "4.8.4"
|
||||
"ts-json-schema-generator": "1.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@openstapps/eslint-config": "workspace:*",
|
||||
"@openstapps/nyc-config": "workspace:*",
|
||||
"@openstapps/prettier-config": "workspace:*",
|
||||
"@openstapps/tsconfig": "workspace:*",
|
||||
"@testdeck/mocha": "0.3.3",
|
||||
"@types/chai": "4.3.4",
|
||||
"@types/fs-extra": "9.0.13",
|
||||
"@types/glob": "8.0.1",
|
||||
@@ -75,10 +70,13 @@
|
||||
"@types/mocha": "10.0.1",
|
||||
"@types/mustache": "4.2.2",
|
||||
"@types/node": "18.15.3",
|
||||
"chai": "4.3.7",
|
||||
"mocha": "10.2.0",
|
||||
"c8": "7.13.0",
|
||||
"nock": "13.3.0",
|
||||
"tsup": "6.7.0",
|
||||
"typedoc": "0.23.28"
|
||||
"ts-node": "10.9.1",
|
||||
"typescript": "4.8.4"
|
||||
},
|
||||
"tsup": {
|
||||
"entry": [
|
||||
@@ -99,8 +97,5 @@
|
||||
"eslintIgnore": [
|
||||
"resources",
|
||||
"openapi"
|
||||
],
|
||||
"nyc": {
|
||||
"extends": "@openstapps/nyc-config"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ import {Command} from 'commander';
|
||||
import {existsSync, readFileSync, writeFileSync} from 'fs';
|
||||
import {copy} from 'fs-extra';
|
||||
import path from 'path';
|
||||
import {mkdirPromisified, readFilePromisified} from './common.js';
|
||||
import {lightweightDefinitionsFromPath, lightweightProjectFromPath} from '@openstapps/easy-ast';
|
||||
import {openapi3Template} from './resources/openapi-303-template.js';
|
||||
import {gatherRouteInformation, generateOpenAPIForRoute} from './routes.js';
|
||||
@@ -27,6 +26,7 @@ import {UMLConfig} from './uml/uml-config.js';
|
||||
import {capitalize} from './util/string.js';
|
||||
import {validateFiles, writeReport} from './validate.js';
|
||||
import {fileURLToPath} from 'url';
|
||||
import {mkdir, readFile} from 'fs/promises';
|
||||
|
||||
// handle unhandled promise rejections
|
||||
process.on('unhandledRejection', async (reason: unknown) => {
|
||||
@@ -42,7 +42,7 @@ const commander = new Command('openstapps-core-tools');
|
||||
// eslint-disable-next-line unicorn/prefer-module
|
||||
commander.version(
|
||||
JSON.parse(
|
||||
readFileSync(path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'package.json')).toString(),
|
||||
readFileSync(path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'package.json')).toString(),
|
||||
).version,
|
||||
);
|
||||
|
||||
@@ -100,7 +100,7 @@ commander
|
||||
// copy schema json schema files
|
||||
try {
|
||||
if (!existsSync(outDirectorySchemasPath)) {
|
||||
await mkdirPromisified(outDirectorySchemasPath, {
|
||||
await mkdir(outDirectorySchemasPath, {
|
||||
recursive: true,
|
||||
});
|
||||
}
|
||||
@@ -134,7 +134,7 @@ commander.command('schema <srcPath> <schemaPath>').action(async (relativeSourceP
|
||||
|
||||
Logger.info(`Found ${validatableTypes.length} type(s) to generate schemas for.`);
|
||||
|
||||
await mkdirPromisified(schemaPath, {
|
||||
await mkdir(schemaPath, {
|
||||
recursive: true,
|
||||
});
|
||||
|
||||
@@ -150,7 +150,7 @@ commander.command('schema <srcPath> <schemaPath>').action(async (relativeSourceP
|
||||
|
||||
Logger.info(`Using ${corePackageJsonPath} to determine version for schemas.`);
|
||||
|
||||
const buffer = await readFilePromisified(corePackageJsonPath);
|
||||
const buffer = await readFile(corePackageJsonPath);
|
||||
const corePackageJson = JSON.parse(buffer.toString());
|
||||
const coreVersion = corePackageJson.version;
|
||||
|
||||
|
||||
@@ -13,17 +13,8 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Logger} from '@openstapps/logger';
|
||||
import {existsSync, mkdir, readFile, unlink, writeFile} from 'fs';
|
||||
import glob from 'glob';
|
||||
import {platform} from 'os';
|
||||
import {promisify} from 'util';
|
||||
import path from 'path';
|
||||
|
||||
export const globPromisified = promisify(glob.Glob);
|
||||
export const mkdirPromisified = promisify(mkdir);
|
||||
export const readFilePromisified = promisify(readFile);
|
||||
export const writeFilePromisified = promisify(writeFile);
|
||||
export const unlinkPromisified = promisify(unlink);
|
||||
import {existsSync} from 'fs';
|
||||
|
||||
/**
|
||||
* Get path that contains a tsconfig.json
|
||||
@@ -33,21 +24,15 @@ export const unlinkPromisified = promisify(unlink);
|
||||
export function getTsconfigPath(startPath: string): string {
|
||||
let tsconfigPath = startPath;
|
||||
|
||||
// see https://stackoverflow.com/questions/9652043/identifying-the-file-system-root-with-node-js
|
||||
const root = platform() === 'win32' ? process.cwd().split(path.sep)[0] : '/';
|
||||
|
||||
// repeat until a tsconfig.json is found
|
||||
while (!existsSync(path.join(tsconfigPath, 'tsconfig.json'))) {
|
||||
if (tsconfigPath === root) {
|
||||
const parent = path.resolve(tsconfigPath, '..');
|
||||
if (tsconfigPath === parent) {
|
||||
throw new Error(
|
||||
`Reached file system root ${root} while searching for 'tsconfig.json' in ${startPath}!`,
|
||||
`Reached file system root ${parent} while searching for 'tsconfig.json' in ${startPath}!`,
|
||||
);
|
||||
}
|
||||
|
||||
// pop last directory
|
||||
const tsconfigPathParts = tsconfigPath.split(path.sep);
|
||||
tsconfigPathParts.pop();
|
||||
tsconfigPath = tsconfigPathParts.join(path.sep);
|
||||
tsconfigPath = parent;
|
||||
}
|
||||
|
||||
Logger.info(`Using 'tsconfig.json' from ${tsconfigPath}.`);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
export * from './validate.js'
|
||||
export * from './types/validator.js'
|
||||
export * from './validate.js';
|
||||
export * from './types/validator.js';
|
||||
|
||||
export * from './uml/uml-config.js'
|
||||
export * from './uml/create-diagram.js'
|
||||
export * from './uml/uml-config.js';
|
||||
export * from './uml/create-diagram.js';
|
||||
|
||||
export * from './routes.js'
|
||||
export * from './types/routes.js'
|
||||
export * from './routes.js';
|
||||
export * from './types/routes.js';
|
||||
|
||||
export * from './schema.js'
|
||||
export * from './types/schema.js'
|
||||
export * from './schema.js';
|
||||
export * from './types/schema.js';
|
||||
|
||||
@@ -13,7 +13,11 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {OpenAPIV3} from 'openapi-types';
|
||||
import {isLightweightClass, lightweightProjectFromPath, LightweightProjectWithIndex} from '@openstapps/easy-ast';
|
||||
import {
|
||||
isLightweightClass,
|
||||
lightweightProjectFromPath,
|
||||
LightweightProjectWithIndex,
|
||||
} from '@openstapps/easy-ast';
|
||||
import {RouteInstanceWithMeta, RouteWithMetaInformation} from './types/routes.js';
|
||||
import {rejectNil} from './util/collections.js';
|
||||
import {capitalize} from './util/string.js';
|
||||
|
||||
@@ -22,7 +22,7 @@ import {getTsconfigPath} from './common.js';
|
||||
import {definitionsOf, lightweightProjectFromPath} from '@openstapps/easy-ast';
|
||||
import {isSchemaWithDefinitions} from './util/guards.js';
|
||||
import path from 'path';
|
||||
import re2 from './types/re2.js';
|
||||
import re2 from 're2';
|
||||
|
||||
/**
|
||||
* StAppsCore converter
|
||||
@@ -64,7 +64,7 @@ export class Converter {
|
||||
this.generator = new SchemaGenerator(program, createParser(program, config), createFormatter(config));
|
||||
|
||||
// create Ajv instance
|
||||
this.schemaValidator = new Ajv.default({code: {regExp: re2}});
|
||||
this.schemaValidator = new Ajv.default({code: {regExp: re2 as never}});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
import re2 from 're2';
|
||||
|
||||
type Re2 = typeof re2 & {code: string};
|
||||
(re2 as Re2).code = 'require("lib/types/re2").default';
|
||||
|
||||
export default re2 as Re2;
|
||||
@@ -13,7 +13,6 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Logger} from '@openstapps/logger';
|
||||
import {createWriteStream} from 'fs';
|
||||
import * as request from 'got';
|
||||
import {
|
||||
expandTypeValue,
|
||||
@@ -22,9 +21,10 @@ import {
|
||||
LightweightClassDefinition,
|
||||
LightweightDefinition,
|
||||
LightweightProperty,
|
||||
LightweightType
|
||||
LightweightType,
|
||||
} from '@openstapps/easy-ast';
|
||||
import {UMLConfig} from './uml-config.js';
|
||||
import {writeFile} from 'fs/promises';
|
||||
|
||||
/**
|
||||
* Converts the lightweight class/enum definitions according to the configuration,
|
||||
@@ -81,8 +81,8 @@ export async function createDiagramFromString(
|
||||
plantUmlBaseURL: string,
|
||||
outputFile = `Diagram-${new Date().toISOString()}`,
|
||||
) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires,unicorn/prefer-module
|
||||
const plantumlEncoder = require('plantuml-encoder');
|
||||
// @ts-expect-error no declarations
|
||||
const plantumlEncoder = await import('plantuml-encoder');
|
||||
const plantUMLCode = plantumlEncoder.encode(`@startuml\n${modelPlantUMLCode}\n@enduml`);
|
||||
const url = `${plantUmlBaseURL}/svg/${plantUMLCode}`;
|
||||
let response;
|
||||
@@ -100,13 +100,10 @@ export async function createDiagramFromString(
|
||||
throw error;
|
||||
}
|
||||
// attach file extension
|
||||
const fileName = `${outputFile}.svg`;
|
||||
try {
|
||||
createWriteStream(fileName).write(response.body);
|
||||
Logger.log(`Writen data to file: ${fileName}`);
|
||||
} catch {
|
||||
throw new Error('Could not write file. Are you missing permissions?');
|
||||
}
|
||||
const fileName = `${outputFile.replace(/[^\w-]/g, '_')}.svg`;
|
||||
|
||||
await writeFile(fileName, response.body);
|
||||
Logger.log(`Writen data to file: ${fileName}`);
|
||||
|
||||
return fileName;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
export function rejectNil<T>(array: Array<T | undefined | null>): T[] {
|
||||
// eslint-disable-next-line unicorn/no-null
|
||||
return array.filter(it => it == null) as T[];
|
||||
return array.filter(it => it != null) as T[];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,16 +15,17 @@
|
||||
import {Logger} from '@openstapps/logger';
|
||||
import Ajv from 'ajv';
|
||||
import betterAjvErrors, {IOutputError} from 'better-ajv-errors';
|
||||
import {PathLike} from 'fs';
|
||||
import type {PathLike} from 'fs';
|
||||
import {readFile, writeFile} from 'fs/promises';
|
||||
import {JSONSchema7} from 'json-schema';
|
||||
import mustache from 'mustache';
|
||||
import {Schema} from 'ts-json-schema-generator';
|
||||
import {globPromisified, readFilePromisified, writeFilePromisified} from './common.js';
|
||||
import {ExpectedValidationErrors, ValidationError, ValidationResult} from './types/validator.js';
|
||||
import {isThingWithType} from './util/guards.js';
|
||||
import path from 'path';
|
||||
import re2 from './types/re2.js';
|
||||
import {toPosixPath} from './util/posix-path.js';
|
||||
import re2 from 're2';
|
||||
import {glob} from 'glob';
|
||||
import {fileURLToPath} from 'url';
|
||||
|
||||
/**
|
||||
* StAppsCore validator
|
||||
@@ -35,13 +36,13 @@ export class Validator {
|
||||
*/
|
||||
private readonly ajv = new Ajv.default({
|
||||
verbose: true,
|
||||
code: {regExp: re2},
|
||||
code: {regExp: re2 as never},
|
||||
});
|
||||
|
||||
/**
|
||||
* Map of schema names to schemas
|
||||
*/
|
||||
private readonly schemas: {[type: string]: Schema} = {};
|
||||
private readonly schemas: { [type: string]: Schema } = {};
|
||||
|
||||
/**
|
||||
* A wrapper function for Ajv that transforms the error into the compatible old error
|
||||
@@ -58,8 +59,9 @@ export class Validator {
|
||||
*
|
||||
* @param schemaDirectory Path to directory that contains schema files
|
||||
*/
|
||||
public async addSchemas(schemaDirectory: PathLike): Promise<string[]> {
|
||||
const schemaFiles = await globPromisified(path.posix.join(toPosixPath(schemaDirectory), '*.json'));
|
||||
public async addSchemas(schemaDirectory: string): Promise<string[]> {
|
||||
const searchGlob = path.posix.join(schemaDirectory.replaceAll(path.sep, path.posix.sep), '*.json');
|
||||
const schemaFiles = await glob(searchGlob);
|
||||
|
||||
if (schemaFiles.length === 0) {
|
||||
throw new Error(`No schema files in ${schemaDirectory.toString()}!`);
|
||||
@@ -70,7 +72,7 @@ export class Validator {
|
||||
await Promise.all(
|
||||
schemaFiles.map(async (file: string) => {
|
||||
// read schema file
|
||||
const buffer = await readFilePromisified(file);
|
||||
const buffer = await readFile(file);
|
||||
|
||||
// add schema to map
|
||||
this.schemas[path.basename(file, '.json')] = JSON.parse(buffer.toString());
|
||||
@@ -92,7 +94,7 @@ export class Validator {
|
||||
if (schema === undefined) {
|
||||
if (isThingWithType(instance)) {
|
||||
// schema name can be inferred from type string
|
||||
const schemaSuffix = (instance as {type: string}).type
|
||||
const schemaSuffix = (instance as { type: string }).type
|
||||
.split(' ')
|
||||
.map((part: string) => {
|
||||
return part.slice(0, 1).toUpperCase() + part.slice(1);
|
||||
@@ -175,8 +177,8 @@ export async function validateFiles(
|
||||
const v = new Validator();
|
||||
await v.addSchemas(schemaDirectory);
|
||||
|
||||
// get list of files to test
|
||||
const testFiles = await globPromisified(path.join(resourcesDirectory, '*.json'));
|
||||
// get a list of files to test
|
||||
const testFiles = await glob(path.posix.join(resourcesDirectory.replaceAll(path.sep, path.posix.sep), '*.json'), {absolute: true});
|
||||
|
||||
if (testFiles.length === 0) {
|
||||
throw new Error(`No test files in ${resourcesDirectory}!`);
|
||||
@@ -191,7 +193,7 @@ export async function validateFiles(
|
||||
testFiles.map(async (testFile: string) => {
|
||||
const testFileName = path.basename(testFile);
|
||||
|
||||
const buffer = await readFilePromisified(path.join(resourcesDirectory, testFileName));
|
||||
const buffer = await readFile(testFile);
|
||||
|
||||
// read test description from file
|
||||
const testDescription = JSON.parse(buffer.toString());
|
||||
@@ -260,12 +262,14 @@ export async function validateFiles(
|
||||
* @param errors Errors that occurred in validation
|
||||
*/
|
||||
export async function writeReport(reportPath: PathLike, errors: ExpectedValidationErrors): Promise<void> {
|
||||
// eslint-disable-next-line unicorn/prefer-module
|
||||
let buffer = await readFilePromisified(path.resolve(__dirname, '..', 'resources', 'file.html.mustache'));
|
||||
let buffer = await readFile(
|
||||
path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'resources', 'file.html.mustache'),
|
||||
);
|
||||
const fileTemplate = buffer.toString();
|
||||
|
||||
// eslint-disable-next-line unicorn/prefer-module
|
||||
buffer = await readFilePromisified(path.resolve(__dirname, '..', 'resources', 'error.html.mustache'));
|
||||
buffer = await readFile(
|
||||
path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'resources', 'error.html.mustache'),
|
||||
);
|
||||
const errorTemplate = buffer.toString();
|
||||
|
||||
let output = '';
|
||||
@@ -295,11 +299,12 @@ export async function writeReport(reportPath: PathLike, errors: ExpectedValidati
|
||||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line unicorn/prefer-module
|
||||
buffer = await readFilePromisified(path.resolve(__dirname, '..', 'resources', 'report.html.mustache'));
|
||||
buffer = await readFile(
|
||||
path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'resources', 'report.html.mustache'),
|
||||
);
|
||||
const reportTemplate = buffer.toString();
|
||||
|
||||
await writeFilePromisified(
|
||||
await writeFile(
|
||||
reportPath,
|
||||
mustache.render(reportTemplate, {
|
||||
report: output,
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
*/
|
||||
import {Logger} from '@openstapps/logger';
|
||||
import {expect} from 'chai';
|
||||
import {slow, suite, test, timeout} from '@testdeck/mocha';
|
||||
import {cwd} from 'process';
|
||||
import {getTsconfigPath} from '../src/common.js';
|
||||
import path from 'path';
|
||||
import {fileURLToPath} from 'url';
|
||||
|
||||
process.on('unhandledRejection', (reason: unknown): void => {
|
||||
if (reason instanceof Error) {
|
||||
@@ -26,10 +26,10 @@ process.on('unhandledRejection', (reason: unknown): void => {
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
@suite(timeout(20_000), slow(10_000))
|
||||
export class CommonSpec {
|
||||
@test
|
||||
async getTsconfigPath() {
|
||||
expect(getTsconfigPath(__dirname)).to.be.equal(cwd());
|
||||
}
|
||||
}
|
||||
describe('common', function () {
|
||||
describe('getTsconfigPath', function () {
|
||||
it('should get tsconfig path', function () {
|
||||
expect(getTsconfigPath(path.dirname(fileURLToPath(import.meta.url)))).to.be.equal(process.cwd());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,36 +14,32 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {expect} from 'chai';
|
||||
import {existsSync, unlinkSync} from 'fs';
|
||||
import {slow, suite, test, timeout} from '@testdeck/mocha';
|
||||
import {createDiagram, createDiagramFromString} from '../src/uml/create-diagram.js';
|
||||
import {UMLConfig} from '../src/uml/uml-config.js';
|
||||
import {LightweightDefinition, lightweightDefinitionsFromPath} from '@openstapps/easy-ast';
|
||||
import {unlink} from 'fs/promises';
|
||||
import {createDiagram, createDiagramFromString} from '../src/index.js';
|
||||
import {UMLConfig} from '../src/index.js';
|
||||
import {lightweightDefinitionsFromPath} from '@openstapps/easy-ast';
|
||||
import nock = require('nock');
|
||||
import path from 'path';
|
||||
import {existsSync} from 'fs';
|
||||
import {fileURLToPath} from 'url';
|
||||
|
||||
@suite(timeout(15_000), slow(5000))
|
||||
export class CreateDiagramSpec {
|
||||
plantUmlConfig: UMLConfig;
|
||||
describe('CreateDiagram', function () {
|
||||
this.timeout(15_000);
|
||||
this.slow(5000);
|
||||
|
||||
definitions: LightweightDefinition[];
|
||||
const plantUmlConfig: UMLConfig = {
|
||||
definitions: [],
|
||||
showAssociations: true,
|
||||
showEnumValues: true,
|
||||
showInheritance: true,
|
||||
showInheritedProperties: true,
|
||||
showOptionalProperties: true,
|
||||
showProperties: true,
|
||||
};
|
||||
|
||||
constructor() {
|
||||
this.plantUmlConfig = {
|
||||
definitions: [],
|
||||
showAssociations: true,
|
||||
showEnumValues: true,
|
||||
showInheritance: true,
|
||||
showInheritedProperties: true,
|
||||
showOptionalProperties: true,
|
||||
showProperties: true,
|
||||
};
|
||||
const definitions = lightweightDefinitionsFromPath('./test/model');
|
||||
|
||||
this.definitions = lightweightDefinitionsFromPath('./test/model');
|
||||
}
|
||||
|
||||
@test
|
||||
async shouldRefuseRequest() {
|
||||
it('should refuse request', async function () {
|
||||
const testPlantUmlCode = 'class Test{\n}';
|
||||
try {
|
||||
await createDiagramFromString(testPlantUmlCode, 'http://plantuml:8080');
|
||||
@@ -54,7 +50,7 @@ export class CreateDiagramSpec {
|
||||
new Error('getaddrinfo ENOTFOUND plantuml').message,
|
||||
]).to.include((error as NodeJS.ErrnoException).message);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* This test will only test the functionality of the method
|
||||
@@ -63,26 +59,25 @@ export class CreateDiagramSpec {
|
||||
* - Writing the response to a file
|
||||
* This test will not check the file content
|
||||
*/
|
||||
@test
|
||||
async shouldCreateDiagrams() {
|
||||
it('should create diagrams', async function () {
|
||||
nock('http://plantuml:8080')
|
||||
.persist()
|
||||
.get(() => true)
|
||||
.reply(200, 'This will be the file content');
|
||||
|
||||
let fileName = await createDiagram(this.definitions, this.plantUmlConfig, 'http://plantuml:8080');
|
||||
let filePath = path.resolve(__dirname, '..', fileName);
|
||||
expect(await existsSync(filePath)).to.equal(true);
|
||||
let fileName = await createDiagram(definitions, plantUmlConfig, 'http://plantuml:8080');
|
||||
let filePath = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', fileName);
|
||||
expect(existsSync(filePath)).to.be.true;
|
||||
|
||||
await unlinkSync(fileName);
|
||||
this.plantUmlConfig.showAssociations = false;
|
||||
await unlink(fileName);
|
||||
plantUmlConfig.showAssociations = false;
|
||||
|
||||
this.plantUmlConfig.showInheritance = false;
|
||||
fileName = await createDiagram(this.definitions, this.plantUmlConfig, 'http://plantuml:8080');
|
||||
filePath = path.resolve(__dirname, '..', fileName);
|
||||
expect(await existsSync(filePath)).to.equal(true);
|
||||
await unlinkSync(fileName);
|
||||
plantUmlConfig.showInheritance = false;
|
||||
fileName = await createDiagram(definitions, plantUmlConfig, 'http://plantuml:8080');
|
||||
filePath = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', fileName);
|
||||
expect(existsSync(filePath)).to.be.true;
|
||||
await unlink(fileName);
|
||||
|
||||
nock.cleanAll();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
*/
|
||||
import {Logger} from '@openstapps/logger';
|
||||
import {expect} from 'chai';
|
||||
import {slow, suite, test, timeout} from '@testdeck/mocha';
|
||||
import {Converter} from '../src/schema.js';
|
||||
import path from 'path';
|
||||
import {fileURLToPath} from 'url';
|
||||
|
||||
process.on('unhandledRejection', (error: unknown) => {
|
||||
if (error instanceof Error) {
|
||||
@@ -26,11 +26,14 @@ process.on('unhandledRejection', (error: unknown) => {
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
@suite(timeout(40_000), slow(10_000))
|
||||
export class SchemaSpec {
|
||||
@test
|
||||
async getSchema() {
|
||||
const converter = new Converter(path.join(__dirname, '..', 'src', 'resources'));
|
||||
describe('Schema', function () {
|
||||
this.timeout(40_000);
|
||||
this.slow(10_000);
|
||||
|
||||
it('should create schema', function () {
|
||||
const converter = new Converter(
|
||||
path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'src', 'resources'),
|
||||
);
|
||||
|
||||
const schema = converter.getSchema('Foo', '0.0.1');
|
||||
expect(schema).to.be.deep.equal({
|
||||
@@ -77,5 +80,5 @@ export class SchemaSpec {
|
||||
required: ['lorem', 'type'],
|
||||
type: 'object',
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,14 +15,14 @@
|
||||
*/
|
||||
import {Logger} from '@openstapps/logger';
|
||||
import {expect} from 'chai';
|
||||
import {existsSync, mkdirSync, writeFileSync} from 'fs';
|
||||
import {existsSync} from 'fs';
|
||||
import {JSONSchema7 as Schema} from 'json-schema';
|
||||
import {slow, suite, test, timeout} from '@testdeck/mocha';
|
||||
import rimraf from 'rimraf';
|
||||
import {Foo} from '../src/resources/foo.js';
|
||||
import {Converter} from '../src/schema.js';
|
||||
import {Validator} from '../src/validate.js';
|
||||
import path from 'path';
|
||||
import {fileURLToPath} from 'url';
|
||||
import {rm, mkdir, writeFile} from 'fs/promises';
|
||||
import {Converter} from '../src/index.js';
|
||||
|
||||
process.on('unhandledRejection', (error: unknown) => {
|
||||
if (error instanceof Error) {
|
||||
@@ -31,57 +31,55 @@ process.on('unhandledRejection', (error: unknown) => {
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
const tmpdir = path.join(__dirname, 'tmp');
|
||||
const tmpdir = path.join(path.dirname(fileURLToPath(import.meta.url)), 'tmp');
|
||||
const fooInstance: Foo = {
|
||||
lorem: 'ipsum',
|
||||
type: 'Foo',
|
||||
};
|
||||
|
||||
@suite(timeout(40_000), slow(5000))
|
||||
export class ValidateSpec {
|
||||
static converter: Converter;
|
||||
describe('Validator', function () {
|
||||
this.timeout(40_000);
|
||||
this.slow(5000);
|
||||
|
||||
static schema: Schema;
|
||||
let schema: Schema;
|
||||
let converter: Converter;
|
||||
|
||||
static before() {
|
||||
this.converter = new Converter(path.join(__dirname, '..', 'src', 'resources'));
|
||||
this.schema = this.converter.getSchema('Foo', '0.0.1');
|
||||
beforeEach(async function () {
|
||||
converter = new Converter(
|
||||
path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'src', 'resources'),
|
||||
);
|
||||
schema = converter.getSchema('Foo', '0.0.1');
|
||||
if (!existsSync(tmpdir)) {
|
||||
mkdirSync(tmpdir);
|
||||
await mkdir(tmpdir);
|
||||
}
|
||||
writeFileSync(path.join(tmpdir, 'SCFoo.json'), JSON.stringify(this.schema, undefined, 2));
|
||||
}
|
||||
await writeFile(path.join(tmpdir, 'SCFoo.json'), JSON.stringify(schema, undefined, 2));
|
||||
});
|
||||
|
||||
static after() {
|
||||
rimraf(tmpdir, error => {
|
||||
// tslint:disable-next-line: no-unused-expression
|
||||
afterEach(async function () {
|
||||
try {
|
||||
await rm(tmpdir, {recursive: true});
|
||||
} catch (error) {
|
||||
expect(error, `Unable to remove temporary directory for tests at: ${tmpdir}`).to.be.null;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async validateBySchemaIdentifyingString() {
|
||||
it('should validate by schema identifying string', async function () {
|
||||
const validator = new Validator();
|
||||
await validator.addSchemas(tmpdir);
|
||||
const validationResult = validator.validate(fooInstance, 'SCFoo');
|
||||
// tslint:disable-next-line: no-unused-expression
|
||||
expect(validationResult.errors, JSON.stringify(validationResult.errors, undefined, 2)).to.be.empty;
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async validateBySchemaInstance() {
|
||||
it('should validate by schema instance', async function () {
|
||||
const validator = new Validator();
|
||||
const validationResult = validator.validate(fooInstance, ValidateSpec.schema);
|
||||
// tslint:disable-next-line: no-unused-expression
|
||||
const validationResult = validator.validate(fooInstance, schema);
|
||||
expect(validationResult.errors, JSON.stringify(validationResult.errors, undefined, 2)).to.be.empty;
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async validateIntrinsic() {
|
||||
it('should validate intrinsic', async function () {
|
||||
const validator = new Validator();
|
||||
await validator.addSchemas(tmpdir);
|
||||
const validationResult = validator.validate(fooInstance);
|
||||
// tslint:disable-next-line: no-unused-expression
|
||||
expect(validationResult.errors, JSON.stringify(validationResult.errors, undefined, 2)).to.be.empty;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -26,15 +26,15 @@
|
||||
"main": "./lib/index.js",
|
||||
"types": "./lib/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "tsup --dts",
|
||||
"format": "prettier .",
|
||||
"format:fix": "prettier --write .",
|
||||
"build": "tsup --dts && pnpm run mappings && pnpm run schema",
|
||||
"format": "prettier . --ignore-path ../../.gitignore",
|
||||
"format:fix": "prettier --write . --ignore-path ../../.gitignore",
|
||||
"lint": "eslint --ext .ts src/",
|
||||
"lint:fix": "eslint --fix --ext .ts src/",
|
||||
"mappings": "openstapps-es-mapping-generator mapping ../core/src -i minlength,pattern,see,tjs-format -m lib/mappings/mappings.json -a lib/mappings/aggregations.json",
|
||||
"mappings-integration": "openstapps-es-mapping-generator put-es-templates lib/mappings/mappings.json http://elasticsearch:9200/",
|
||||
"schema": "node --max-old-space-size=8192 --stack-size=10240 ./node_modules/@openstapps/core-tools/lib/cli.js schema src lib/schema",
|
||||
"test": "nyc mocha --recursive 'test/*.spec.ts'"
|
||||
"schema": "node --max-old-space-size=8192 --stack-size=10240 ./node_modules/@openstapps/core-tools/lib/app.js schema src lib/schema",
|
||||
"test": "c8 mocha"
|
||||
},
|
||||
"dependencies": {
|
||||
"@openstapps/core-tools": "workspace:*",
|
||||
@@ -51,7 +51,7 @@
|
||||
"@openstapps/logger": "workspace:*",
|
||||
"@openstapps/prettier-config": "workspace:*",
|
||||
"@openstapps/tsconfig": "workspace:*",
|
||||
"@testdeck/mocha": "0.3.3",
|
||||
"@openstapps/easy-ast": "workspace:*",
|
||||
"@types/chai": "4.3.4",
|
||||
"@types/json-patch": "0.0.30",
|
||||
"@types/json-schema": "7.0.11",
|
||||
@@ -62,8 +62,7 @@
|
||||
"chai": "4.3.7",
|
||||
"conditional-type-checks": "1.0.6",
|
||||
"mocha": "10.2.0",
|
||||
"nyc": "15.1.0",
|
||||
"rimraf": "4.4.0",
|
||||
"c8": "7.13.0",
|
||||
"source-map-support": "0.5.21",
|
||||
"surge": "0.23.1",
|
||||
"ts-node": "10.9.1",
|
||||
@@ -115,12 +114,10 @@
|
||||
"resources",
|
||||
"openapi"
|
||||
],
|
||||
"nyc": {
|
||||
"extends": "@openstapps/nyc-config"
|
||||
},
|
||||
"openstapps-configuration": {
|
||||
"overrides": [
|
||||
"lint"
|
||||
"lint",
|
||||
"build"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import equal from 'fast-deep-equal/es6';
|
||||
import equal from 'fast-deep-equal/es6/index.js';
|
||||
import clone from 'rfdc';
|
||||
import {SCLanguageCode} from './general/i18n.js';
|
||||
import {isThing} from './guards.js';
|
||||
|
||||
@@ -13,41 +13,31 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {lightweightProjectFromPath} from '@openstapps/core-tools/lib/easy-ast/easy-ast';
|
||||
import {LightweightProject} from '@openstapps/core-tools/lib/easy-ast/types/lightweight-project';
|
||||
import {lightweightProjectFromPath, LightweightProject} from '@openstapps/easy-ast';
|
||||
import {expect} from 'chai';
|
||||
import {reduce} from 'lodash';
|
||||
|
||||
process.on('unhandledRejection', err => {
|
||||
throw err;
|
||||
process.on('unhandledRejection', error => {
|
||||
throw error;
|
||||
});
|
||||
|
||||
describe('Mapping Compatibility', () => {
|
||||
let project: LightweightProject;
|
||||
|
||||
before(function () {
|
||||
this.timeout(15000);
|
||||
this.slow(10000);
|
||||
this.timeout(15_000);
|
||||
this.slow(10_000);
|
||||
|
||||
project = lightweightProjectFromPath('src');
|
||||
});
|
||||
|
||||
it('non-exported definitions should not have duplicate names across files', () => {
|
||||
reduce(
|
||||
project,
|
||||
(result, file) =>
|
||||
reduce(
|
||||
file,
|
||||
(result2, _, key) => {
|
||||
expect(result2[key]).to.be.undefined;
|
||||
return {
|
||||
[key]: true,
|
||||
...result2,
|
||||
};
|
||||
},
|
||||
result,
|
||||
),
|
||||
{} as Record<string, boolean>,
|
||||
);
|
||||
const names = new Set<string>();
|
||||
|
||||
for (const file in project) {
|
||||
for (const definition in project[file]) {
|
||||
expect(names).not.to.include(definition);
|
||||
names.add(definition);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
33
packages/core/test/dummy/building.ts
Normal file
33
packages/core/test/dummy/building.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import {SCBuildingWithoutReferences, SCThingType} from '../../src/index.js';
|
||||
|
||||
export const building: SCBuildingWithoutReferences = {
|
||||
address: {
|
||||
addressCountry: 'base-address.addressCountry',
|
||||
addressLocality: 'base-address.addressLocality',
|
||||
postalCode: 'base-address.postalCode',
|
||||
streetAddress: 'base-address.streetAddress',
|
||||
},
|
||||
categories: ['office', 'education'],
|
||||
floors: ['base-floor0', 'base-floor1'],
|
||||
geo: {
|
||||
point: {
|
||||
coordinates: [12, 13],
|
||||
type: 'Point',
|
||||
},
|
||||
},
|
||||
name: 'base-space-name',
|
||||
translations: {
|
||||
de: {
|
||||
address: {
|
||||
addressCountry: 'de-address.addressCountry',
|
||||
addressLocality: 'de-address.addressLocality',
|
||||
postalCode: 'de-address.postalCode',
|
||||
streetAddress: 'de-address.streetAddress',
|
||||
},
|
||||
floors: ['de-floor0', 'de-floor1'],
|
||||
name: 'de-space-name',
|
||||
},
|
||||
},
|
||||
type: SCThingType.Building,
|
||||
uid: '540862f3-ea30-5b8f-8678-56b4dc217140',
|
||||
};
|
||||
9
packages/core/test/dummy/bulk-response.ts
Normal file
9
packages/core/test/dummy/bulk-response.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import {SCBulkResponse, SCThingType} from '../../src/index.js';
|
||||
|
||||
export const bulkResponse: SCBulkResponse = {
|
||||
expiration: '2009-06-30T18:30:00+02:00 ',
|
||||
source: 'bar',
|
||||
state: 'done',
|
||||
type: SCThingType.Dish,
|
||||
uid: 'foo',
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
import {SCSearchResponse} from '../../src/index.js';
|
||||
import {dishWithTranslation} from './dish-with-translation.js';
|
||||
|
||||
export const dishWithTranslationSearchResponse: SCSearchResponse = {
|
||||
data: [dishWithTranslation],
|
||||
facets: [
|
||||
{
|
||||
buckets: [
|
||||
{
|
||||
count: 1,
|
||||
key: 'key',
|
||||
},
|
||||
],
|
||||
field: 'field',
|
||||
},
|
||||
],
|
||||
pagination: {
|
||||
count: 1,
|
||||
offset: 0,
|
||||
total: 1,
|
||||
},
|
||||
stats: {
|
||||
time: 1,
|
||||
},
|
||||
};
|
||||
17
packages/core/test/dummy/dish-with-translation.ts
Normal file
17
packages/core/test/dummy/dish-with-translation.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import {SCDish, SCThingOriginType, SCThingType} from '../../src/index.js';
|
||||
|
||||
export const dishWithTranslation: SCDish = {
|
||||
categories: ['appetizer'],
|
||||
name: 'foo',
|
||||
origin: {
|
||||
created: '',
|
||||
type: SCThingOriginType.User,
|
||||
},
|
||||
translations: {
|
||||
de: {
|
||||
name: 'Foo',
|
||||
},
|
||||
},
|
||||
type: SCThingType.Dish,
|
||||
uid: 'bar',
|
||||
};
|
||||
35
packages/core/test/dummy/dish.ts
Normal file
35
packages/core/test/dummy/dish.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import {SCDish, SCThingOriginType, SCThingType} from '../../src/index.js';
|
||||
import {building} from './building.js';
|
||||
|
||||
export const dish: SCDish = {
|
||||
categories: ['main dish', 'dessert'],
|
||||
characteristics: [{name: 'base-characteristic0'}, {name: 'base-characteristic1'}],
|
||||
name: 'base-dish-name',
|
||||
offers: [
|
||||
{
|
||||
availability: 'in stock',
|
||||
inPlace: building,
|
||||
prices: {
|
||||
default: 23.42,
|
||||
},
|
||||
provider: {
|
||||
name: 'base-provider',
|
||||
type: SCThingType.Organization,
|
||||
uid: '540862f3-ea30-5b8f-8678-56b4dc217141',
|
||||
},
|
||||
},
|
||||
],
|
||||
origin: {
|
||||
indexed: '1970-01-01T00:00:00.000Z',
|
||||
name: 'dish-connector',
|
||||
type: SCThingOriginType.Remote,
|
||||
},
|
||||
translations: {
|
||||
de: {
|
||||
characteristics: [{name: 'de-characteristic0'}, {name: 'de-characteristic1'}],
|
||||
name: 'de-dish-name',
|
||||
},
|
||||
},
|
||||
type: SCThingType.Dish,
|
||||
uid: '540862f3-ea30-5b8f-8678-56b4dc217140',
|
||||
};
|
||||
13
packages/core/test/dummy/not-a-dish.ts
Normal file
13
packages/core/test/dummy/not-a-dish.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import {SCThingOriginType} from '../../src/index.js';
|
||||
import {SCDish} from '../../lib/index.js';
|
||||
|
||||
export const notADish: Omit<SCDish, 'type'> & {type: 'foobar'} = {
|
||||
categories: ['appetizer'],
|
||||
name: 'foo',
|
||||
origin: {
|
||||
created: '',
|
||||
type: SCThingOriginType.User,
|
||||
},
|
||||
type: 'foobar',
|
||||
uid: 'bar',
|
||||
};
|
||||
18
packages/core/test/dummy/setting.ts
Normal file
18
packages/core/test/dummy/setting.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import {SCSetting, SCSettingInputType, SCThingOriginType, SCThingType} from '../../src/index.js';
|
||||
|
||||
export const setting: SCSetting = {
|
||||
categories: ['profile'],
|
||||
defaultValue: 'student',
|
||||
description: 'base-description',
|
||||
inputType: SCSettingInputType.SingleChoice,
|
||||
name: 'group',
|
||||
order: 1,
|
||||
origin: {
|
||||
indexed: '2018-11-11T14:30:00Z',
|
||||
name: 'Dummy',
|
||||
type: SCThingOriginType.Remote,
|
||||
},
|
||||
type: SCThingType.Setting,
|
||||
uid: '2c97aa36-4aa2-43de-bc5d-a2b2cb3a530e',
|
||||
values: ['student', 'employee', true, 42],
|
||||
};
|
||||
@@ -16,18 +16,17 @@ import {
|
||||
isLightweightClass,
|
||||
isLightweightEnum,
|
||||
isUnionType,
|
||||
} from '@openstapps/core-tools/lib/easy-ast/ast-util';
|
||||
import {LightweightAliasDefinition} from '@openstapps/core-tools/lib/easy-ast/types/lightweight-alias-definition';
|
||||
import {LightweightProjectWithIndex} from '@openstapps/core-tools/lib/easy-ast/types/lightweight-project';
|
||||
import {LightweightType} from '@openstapps/core-tools/lib/easy-ast/types/lightweight-type';
|
||||
import {LightweightClassDefinition} from '@openstapps/core-tools/src/easy-ast/types/lightweight-class-definition';
|
||||
import {LightweightDefinition} from '@openstapps/core-tools/src/easy-ast/types/lightweight-definition';
|
||||
import {LightweightProperty} from '@openstapps/core-tools/src/easy-ast/types/lightweight-property';
|
||||
LightweightAliasDefinition,
|
||||
LightweightProjectWithIndex,
|
||||
LightweightType,
|
||||
LightweightClassDefinition,
|
||||
LightweightDefinition,
|
||||
LightweightProperty,
|
||||
} from '@openstapps/easy-ast';
|
||||
import {expect} from 'chai';
|
||||
import {assign, chain, clone, flatMap, isNil, reduce, reject, some} from 'lodash';
|
||||
|
||||
process.on('unhandledRejection', err => {
|
||||
throw err;
|
||||
process.on('unhandledRejection', error => {
|
||||
throw error;
|
||||
});
|
||||
|
||||
describe('Features', () => {
|
||||
@@ -37,8 +36,8 @@ describe('Features', () => {
|
||||
let thingsWithoutReferences: LightweightClassDefinition[];
|
||||
|
||||
before(function () {
|
||||
this.timeout(15000);
|
||||
this.slow(10000);
|
||||
this.timeout(15_000);
|
||||
this.slow(10_000);
|
||||
|
||||
project = new LightweightProjectWithIndex('src');
|
||||
|
||||
@@ -51,9 +50,7 @@ describe('Features', () => {
|
||||
referenceName: 'SCDiff',
|
||||
});
|
||||
|
||||
expect(
|
||||
thingsReflection.type?.specificationTypes?.every(it => typeof it.referenceName !== 'undefined'),
|
||||
).to.be.true;
|
||||
expect(thingsReflection.type?.specificationTypes?.map(it => it.referenceName)).not.to.include(undefined);
|
||||
thingNames = thingsReflection.type?.specificationTypes?.map(type => type.referenceName!) ?? [];
|
||||
things = thingNames.map(it => project.definitions[it]).filter(isLightweightClass);
|
||||
thingsWithoutReferences = thingNames
|
||||
@@ -64,15 +61,22 @@ describe('Features', () => {
|
||||
const inheritedProperties = function (
|
||||
classLike: LightweightClassDefinition,
|
||||
): Record<string, LightweightProperty> | undefined {
|
||||
return reduce(
|
||||
[...(classLike.implementedDefinitions ?? []), ...(classLike.extendedDefinitions ?? [])],
|
||||
(obj, extension) => {
|
||||
const object = project.definitions[extension.referenceName ?? ''];
|
||||
const extendClause = [
|
||||
...(classLike.implementedDefinitions ?? []),
|
||||
...(classLike.extendedDefinitions ?? []),
|
||||
];
|
||||
const properties = {...classLike.properties};
|
||||
|
||||
return assign(obj, isLightweightClass(object) ? inheritedProperties(object) : obj);
|
||||
},
|
||||
clone(classLike.properties),
|
||||
);
|
||||
for (const definition of extendClause) {
|
||||
const object = project.definitions[definition.referenceName!];
|
||||
if (isLightweightClass(object)) {
|
||||
Object.assign(properties, inheritedProperties(object));
|
||||
} else {
|
||||
Object.assign(properties, object);
|
||||
}
|
||||
}
|
||||
|
||||
return properties;
|
||||
};
|
||||
|
||||
it('should have an origin', () => {
|
||||
@@ -82,42 +86,36 @@ describe('Features', () => {
|
||||
});
|
||||
|
||||
it('should not have duplicate names', () => {
|
||||
reduce(
|
||||
project.files,
|
||||
(fileResult, file) =>
|
||||
reduce(
|
||||
file,
|
||||
(definitionResult, definition: LightweightDefinition) => {
|
||||
expect(definitionResult[definition.name]).to.be.undefined;
|
||||
definitionResult[definition.name] = true; // something that's not undefined
|
||||
const names = new Set<string>();
|
||||
|
||||
return definitionResult;
|
||||
},
|
||||
fileResult,
|
||||
),
|
||||
{} as Record<string, true>,
|
||||
);
|
||||
for (const fileName in project.files) {
|
||||
const file = project.files[fileName];
|
||||
for (const definition in file) {
|
||||
const definitionName = file[definition].name;
|
||||
expect(names).not.to.include(definitionName);
|
||||
names.add(definitionName);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('should not have properties referencing SCThing', () => {
|
||||
const allPropertyReferenceNames: (property: LightweightProperty) => string[] = property =>
|
||||
reject(
|
||||
[property.type.referenceName!, ...flatMap(property.properties, allPropertyReferenceNames)],
|
||||
isNil,
|
||||
);
|
||||
[
|
||||
property.type.referenceName!,
|
||||
...Object.values(property.properties ?? []).flatMap(allPropertyReferenceNames),
|
||||
].filter(it => !!it);
|
||||
|
||||
const typeHasSCThingReferences: (type?: LightweightType) => boolean = type =>
|
||||
type?.referenceName
|
||||
? hasSCThingReferences(project.definitions[type.referenceName])
|
||||
: some(type?.specificationTypes, typeHasSCThingReferences);
|
||||
: type?.specificationTypes?.some(typeHasSCThingReferences) === true;
|
||||
|
||||
const hasSCThingReferences: (definition?: LightweightDefinition) => boolean = definition =>
|
||||
isLightweightClass(definition)
|
||||
? chain(inheritedProperties(definition))
|
||||
.flatMap(it => flatMap(it.properties, allPropertyReferenceNames))
|
||||
? Object.values(inheritedProperties(definition) ?? [])
|
||||
.flatMap(it => Object.values(it.properties ?? []).flatMap(allPropertyReferenceNames))
|
||||
.map(it => project.definitions[it] as LightweightDefinition)
|
||||
.some(it => it.name === 'SCThing' || hasSCThingReferences(it))
|
||||
.value()
|
||||
: definition
|
||||
? typeHasSCThingReferences(definition.type)
|
||||
: false;
|
||||
@@ -127,16 +125,18 @@ describe('Features', () => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks if a definition is an SCThing
|
||||
*/
|
||||
function extendsSCThing(definition?: LightweightDefinition): boolean {
|
||||
return isLightweightClass(definition)
|
||||
? chain([
|
||||
? [
|
||||
...((definition as LightweightClassDefinition).extendedDefinitions ?? []),
|
||||
...((definition as LightweightClassDefinition).implementedDefinitions ?? []),
|
||||
])
|
||||
]
|
||||
.map(it => it.referenceName)
|
||||
.reject(isNil)
|
||||
.filter(it => !!it)
|
||||
.some(it => it === 'SCThing' || extendsSCThing(project.definitions[it!]))
|
||||
.value()
|
||||
: false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable unicorn/no-null */
|
||||
/*
|
||||
* Copyright (C) 2018, 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
@@ -12,12 +13,7 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {slow, suite, test, timeout} from '@testdeck/mocha';
|
||||
import {SCBulkResponse} from '../src/protocol/routes/bulk-request.js';
|
||||
import {SCMultiSearchResponse} from '../src/protocol/routes/search-multi.js';
|
||||
import {SCSearchResponse} from '../src/protocol/routes/search.js';
|
||||
import {SCThingOriginType, SCThingType} from '../src/things/abstract/thing.js';
|
||||
import {SCDish} from '../src/things/dish.js';
|
||||
import {SCMultiSearchResponse} from '../src/index.js';
|
||||
import {expect} from 'chai';
|
||||
import {
|
||||
isBulkResponse,
|
||||
@@ -26,117 +22,104 @@ import {
|
||||
isThing,
|
||||
isThingWithTranslations,
|
||||
} from '../src/guards.js';
|
||||
import {bulkResponse} from './dummy/bulk-response.js';
|
||||
import {dishWithTranslation} from './dummy/dish-with-translation.js';
|
||||
import {dishWithTranslationSearchResponse} from './dummy/dish-with-translation-search-response.js';
|
||||
import {notADish} from './dummy/not-a-dish.js';
|
||||
import {SCBulkResponse} from '../src/protocol/routes/bulk-request.js';
|
||||
import {SCSearchResponse} from '../src/protocol/routes/search.js';
|
||||
import {SCMultiSearchResponse} from '../src/protocol/routes/search-multi.js';
|
||||
import {SCThingOriginType, SCThingType} from '../src/things/abstract/thing.js';
|
||||
import {SCDish} from '../src/things/dish';
|
||||
import {SCDish} from '../src/things/dish.js';
|
||||
|
||||
@suite(timeout(10000), slow(5000))
|
||||
export class GuardsSpec {
|
||||
static bulkResponse: SCBulkResponse = {
|
||||
expiration: '2009-06-30T18:30:00+02:00 ',
|
||||
source: 'bar',
|
||||
state: 'done',
|
||||
type: SCThingType.Dish,
|
||||
uid: 'foo',
|
||||
};
|
||||
describe('Guards', function () {
|
||||
this.timeout(10_000);
|
||||
this.slow(5000);
|
||||
|
||||
static dishWithTranslation: SCDish = {
|
||||
categories: ['appetizer'],
|
||||
name: 'foo',
|
||||
origin: {
|
||||
created: '',
|
||||
type: SCThingOriginType.User,
|
||||
},
|
||||
translations: {
|
||||
de: {
|
||||
name: 'Foo',
|
||||
},
|
||||
},
|
||||
type: SCThingType.Dish,
|
||||
uid: 'bar',
|
||||
};
|
||||
describe('isBulkResponse', function () {
|
||||
it(`should not accept nullish values`, function () {
|
||||
expect(isBulkResponse(null)).to.be.false;
|
||||
});
|
||||
|
||||
static notADish = {
|
||||
categories: ['appetizer'],
|
||||
name: 'foo',
|
||||
origin: {
|
||||
created: '',
|
||||
type: SCThingOriginType.User,
|
||||
},
|
||||
type: 'foobar',
|
||||
uid: 'bar',
|
||||
};
|
||||
it('should not accept a dish', function () {
|
||||
expect(isBulkResponse(dishWithTranslation)).to.be.false;
|
||||
});
|
||||
|
||||
static searchResponse: SCSearchResponse = {
|
||||
data: [GuardsSpec.dishWithTranslation],
|
||||
facets: [
|
||||
{
|
||||
buckets: [
|
||||
{
|
||||
count: 1,
|
||||
key: 'key',
|
||||
},
|
||||
],
|
||||
field: 'field',
|
||||
},
|
||||
],
|
||||
pagination: {
|
||||
count: 1,
|
||||
offset: 0,
|
||||
total: 1,
|
||||
},
|
||||
stats: {
|
||||
time: 1,
|
||||
},
|
||||
};
|
||||
it('should accept a bulk', function () {
|
||||
expect(isBulkResponse(bulkResponse)).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
@test
|
||||
public isBulkResponse() {
|
||||
expect(isBulkResponse(null)).to.be.equal(false);
|
||||
expect(isBulkResponse(GuardsSpec.dishWithTranslation)).to.be.equal(false);
|
||||
expect(isBulkResponse(GuardsSpec.bulkResponse)).to.be.equal(true);
|
||||
}
|
||||
|
||||
@test
|
||||
public isMultiSearchResponse() {
|
||||
describe('isMultiSearchResponse', function () {
|
||||
const multiSearchResponse: SCMultiSearchResponse = {
|
||||
foo: GuardsSpec.searchResponse,
|
||||
foo: dishWithTranslationSearchResponse,
|
||||
};
|
||||
expect(isMultiSearchResponse(multiSearchResponse)).to.be.equal(true);
|
||||
const notAMultiSearchResponse = {...multiSearchResponse, ...{bar: 'baz'}};
|
||||
expect(isMultiSearchResponse(notAMultiSearchResponse)).to.be.equal(false);
|
||||
delete multiSearchResponse.foo;
|
||||
expect(isMultiSearchResponse(multiSearchResponse)).to.be.equal(false);
|
||||
}
|
||||
|
||||
@test
|
||||
public isSearchResponse() {
|
||||
const notASearchResponse = {...GuardsSpec.searchResponse};
|
||||
// @ts-ignore
|
||||
delete notASearchResponse.pagination;
|
||||
expect(isSearchResponse(notASearchResponse)).to.be.equal(false);
|
||||
// @ts-ignore
|
||||
delete notASearchResponse.data;
|
||||
expect(isSearchResponse(notASearchResponse)).to.be.equal(false);
|
||||
expect(isSearchResponse(null)).to.be.equal(false);
|
||||
expect(isSearchResponse(GuardsSpec.searchResponse)).to.be.equal(true);
|
||||
}
|
||||
it('should accept a multi search response', function () {
|
||||
expect(isMultiSearchResponse(multiSearchResponse)).to.be.true;
|
||||
});
|
||||
|
||||
@test
|
||||
public isThing() {
|
||||
expect(isThing('foo')).to.be.equal(false);
|
||||
expect(isThing({type: 'foo'})).to.be.equal(false);
|
||||
expect(isThing(GuardsSpec.notADish)).to.be.equal(false);
|
||||
expect(isThing(GuardsSpec.dishWithTranslation)).to.be.equal(true);
|
||||
}
|
||||
it('should not accept a multi search response with invalid search requests', function () {
|
||||
const notAMultiSearchResponse = {...multiSearchResponse, bar: 'baz'};
|
||||
expect(isMultiSearchResponse(notAMultiSearchResponse)).to.be.false;
|
||||
});
|
||||
|
||||
@test
|
||||
public isThingWithTranslations() {
|
||||
const dishWithoutTranslation = {...GuardsSpec.dishWithTranslation};
|
||||
delete dishWithoutTranslation.translations;
|
||||
expect(isThingWithTranslations(dishWithoutTranslation)).to.be.equal(false);
|
||||
expect(isThingWithTranslations(GuardsSpec.dishWithTranslation)).to.be.equal(true);
|
||||
}
|
||||
}
|
||||
it('should not accept empty responses', function () {
|
||||
expect(isMultiSearchResponse({})).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
describe('isSearchResponse', function () {
|
||||
it('should accept a search response', function () {
|
||||
expect(isSearchResponse(dishWithTranslationSearchResponse)).to.be.true;
|
||||
});
|
||||
|
||||
it('should not accept nullish values', function () {
|
||||
expect(isSearchResponse(null)).to.be.false;
|
||||
});
|
||||
|
||||
it('should not accept a response without pagination', function () {
|
||||
const response = {...dishWithTranslationSearchResponse};
|
||||
// @ts-expect-error this is on purpose of course
|
||||
delete response.pagination;
|
||||
expect(isSearchResponse(response)).to.be.false;
|
||||
});
|
||||
|
||||
it('should not accept a response without data', function () {
|
||||
const response = {...dishWithTranslationSearchResponse};
|
||||
// @ts-expect-error this is on purpose of course
|
||||
delete response.data;
|
||||
expect(isSearchResponse(response)).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
describe('isThing', function () {
|
||||
it('should not accept strings', function () {
|
||||
expect(isThing('foo')).to.be.false;
|
||||
});
|
||||
|
||||
it('should not accept objects with arbitrary type values', function () {
|
||||
expect(isThing({type: 'foo'})).to.be.false;
|
||||
});
|
||||
|
||||
it('should not accept things with missing props', function () {
|
||||
expect(isThing(notADish)).to.be.false;
|
||||
});
|
||||
|
||||
it('should accept valid things', function () {
|
||||
expect(isThing(dishWithTranslation)).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
describe('isThingWithTranslations', function () {
|
||||
it('should not accept things without translations', function () {
|
||||
const dishWithoutTranslation = {...dishWithTranslation};
|
||||
delete dishWithoutTranslation.translations;
|
||||
expect(isThingWithTranslations(dishWithoutTranslation)).to.be.false;
|
||||
});
|
||||
|
||||
it('should accept things with translations', function () {
|
||||
expect(isThingWithTranslations(dishWithTranslation)).to.be.true;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,69 +14,51 @@
|
||||
*/
|
||||
import {slow, suite, test, timeout} from '@testdeck/mocha';
|
||||
import {expect} from 'chai';
|
||||
import {slow, suite, test, timeout} from '@testdeck/mocha';
|
||||
import {SCBulkRoute} from '../src/protocol/routes/bulk-request.js';
|
||||
import {SCBulkAddRoute} from '../src/protocol/routes/bulk-add.js';
|
||||
import {SCThingUpdateRoute} from '../src/protocol/routes/thing-update.js';
|
||||
import {SCBulkRoute} from '../src/index.js';
|
||||
import {SCBulkAddRoute} from '../src/index.js';
|
||||
import {SCThingUpdateRoute} from '../src/index.js';
|
||||
|
||||
@suite(timeout(10000), slow(5000))
|
||||
export class RoutesSpec {
|
||||
@test
|
||||
public bulkAddRouteUrlPath() {
|
||||
const bulkAddRoute = new SCBulkAddRoute();
|
||||
describe('Routes', function () {
|
||||
this.timeout(10_000);
|
||||
this.slow(5000);
|
||||
|
||||
it('should produce correct BulkAddRoute url path', function () {
|
||||
expect(
|
||||
bulkAddRoute.getUrlPath({
|
||||
new SCBulkAddRoute().getUrlPath({
|
||||
UID: '540862f3-ea30-5b8f-8678-56b4dc217140',
|
||||
}),
|
||||
).to.equal('/bulk/540862f3-ea30-5b8f-8678-56b4dc217140');
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
public bulkRouteUrlPath() {
|
||||
const bulkRoute = new SCBulkRoute();
|
||||
|
||||
expect(bulkRoute.getUrlPath()).to.equal('/bulk');
|
||||
}
|
||||
|
||||
@test
|
||||
public thingUpdateRouteUrlPath() {
|
||||
const thingUpdateRoute = new SCThingUpdateRoute();
|
||||
it('should produce correct BlukRoute url path', function () {
|
||||
expect(new SCBulkRoute().getUrlPath()).to.equal('/bulk');
|
||||
});
|
||||
|
||||
it('should produce correct ThingUpdateRoute url path', function () {
|
||||
expect(
|
||||
thingUpdateRoute.getUrlPath({
|
||||
new SCThingUpdateRoute().getUrlPath({
|
||||
TYPE: 'dish',
|
||||
UID: '540862f3-ea30-5b8f-8678-56b4dc217140',
|
||||
}),
|
||||
).to.equal('/dish/540862f3-ea30-5b8f-8678-56b4dc217140');
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
public tooManyParameters() {
|
||||
const thingUpdateRoute = new SCThingUpdateRoute();
|
||||
|
||||
const fn = () => {
|
||||
thingUpdateRoute.getUrlPath({
|
||||
it('should throw an error if too many parameters are provided', function () {
|
||||
expect(() =>
|
||||
new SCThingUpdateRoute().getUrlPath({
|
||||
FOO: 'bar',
|
||||
TYPE: 'dish',
|
||||
UID: '540862f3-ea30-5b8f-8678-56b4dc217140',
|
||||
});
|
||||
};
|
||||
}),
|
||||
).to.throw('Extraneous parameters provided.');
|
||||
});
|
||||
|
||||
expect(fn).to.throw('Extraneous parameters provided.');
|
||||
}
|
||||
|
||||
@test
|
||||
public wrongParameters() {
|
||||
const thingUpdateRoute = new SCThingUpdateRoute();
|
||||
|
||||
const fn = () => {
|
||||
thingUpdateRoute.getUrlPath({
|
||||
it('should throw an error if wrong parameters are provided', function () {
|
||||
expect(() =>
|
||||
new SCThingUpdateRoute().getUrlPath({
|
||||
TYPO: 'dish',
|
||||
UID: '540862f3-ea30-5b8f-8678-56b4dc217140',
|
||||
});
|
||||
};
|
||||
|
||||
expect(fn).to.throw("Parameter 'TYPE' not provided.");
|
||||
}
|
||||
}
|
||||
}),
|
||||
).to.throw("Parameter 'TYPE' not provided.");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,29 +1,22 @@
|
||||
import {validateFiles, writeReport} from '@openstapps/core-tools/lib/validate';
|
||||
import {slow, suite, test, timeout} from '@testdeck/mocha';
|
||||
import {validateFiles, writeReport} from '@openstapps/core-tools';
|
||||
import {expect} from 'chai';
|
||||
import {mkdirSync} from 'fs';
|
||||
import {join, resolve} from 'path';
|
||||
import {mkdir} from 'fs/promises';
|
||||
import path from 'path';
|
||||
|
||||
@suite(timeout(15000), slow(10000))
|
||||
export class SchemaSpec {
|
||||
@test
|
||||
async 'validate against test files'() {
|
||||
const errorsPerFile = {
|
||||
...(await validateFiles(resolve('lib', 'schema'), resolve('test', 'resources'))),
|
||||
...(await validateFiles(resolve('lib', 'schema'), resolve('test', 'resources', 'indexable'))),
|
||||
};
|
||||
describe('Schema', function () {
|
||||
this.timeout(15_000);
|
||||
this.slow(10_000);
|
||||
|
||||
let unexpected = false;
|
||||
Object.keys(errorsPerFile).forEach(file => {
|
||||
unexpected = unexpected || errorsPerFile[file].some(error => !error.expected);
|
||||
});
|
||||
it('should validate against test files', async function () {
|
||||
const errorsPerFile = await validateFiles(path.resolve('lib', 'schema'), path.resolve('test', 'resources'));
|
||||
|
||||
mkdirSync('report', {
|
||||
recursive: true,
|
||||
});
|
||||
await mkdir('report', {recursive: true});
|
||||
await writeReport(path.join('report', 'index.html'), errorsPerFile);
|
||||
|
||||
await writeReport(join('report', 'index.html'), errorsPerFile);
|
||||
|
||||
expect(unexpected).to.be.equal(false);
|
||||
}
|
||||
}
|
||||
for (const file of Object.keys(errorsPerFile)) {
|
||||
for (const error of errorsPerFile[file]) {
|
||||
expect(error.expected).to.be.true;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,93 +15,11 @@
|
||||
import {slow, suite, test, timeout} from '@testdeck/mocha';
|
||||
import {expect} from 'chai';
|
||||
import clone from 'rfdc';
|
||||
import {SCThingOriginType, SCThingRemoteOrigin, SCThingType} from '../src/things/abstract/thing.js';
|
||||
import {SCBuildingWithoutReferences} from '../src/things/building.js';
|
||||
import {SCDish, SCDishMeta} from '../src/things/dish.js';
|
||||
import {SCSetting, SCSettingInputType} from '../src/things/setting.js';
|
||||
import {SCThingTranslator} from '../src/translator.js';
|
||||
|
||||
const building: SCBuildingWithoutReferences = {
|
||||
address: {
|
||||
addressCountry: 'base-address.addressCountry',
|
||||
addressLocality: 'base-address.addressLocality',
|
||||
postalCode: 'base-address.postalCode',
|
||||
streetAddress: 'base-address.streetAddress',
|
||||
},
|
||||
categories: ['office', 'education'],
|
||||
floors: ['base-floor0', 'base-floor1'],
|
||||
geo: {
|
||||
point: {
|
||||
coordinates: [12.0, 13.0],
|
||||
type: 'Point',
|
||||
},
|
||||
},
|
||||
name: 'base-space-name',
|
||||
translations: {
|
||||
de: {
|
||||
address: {
|
||||
addressCountry: 'de-address.addressCountry',
|
||||
addressLocality: 'de-address.addressLocality',
|
||||
postalCode: 'de-address.postalCode',
|
||||
streetAddress: 'de-address.streetAddress',
|
||||
},
|
||||
floors: ['de-floor0', 'de-floor1'],
|
||||
name: 'de-space-name',
|
||||
},
|
||||
},
|
||||
type: SCThingType.Building,
|
||||
uid: '540862f3-ea30-5b8f-8678-56b4dc217140',
|
||||
};
|
||||
|
||||
const dish: SCDish = {
|
||||
categories: ['main dish', 'dessert'],
|
||||
characteristics: [{name: 'base-characteristic0'}, {name: 'base-characteristic1'}],
|
||||
name: 'base-dish-name',
|
||||
offers: [
|
||||
{
|
||||
availability: 'in stock',
|
||||
inPlace: building,
|
||||
prices: {
|
||||
default: 23.42,
|
||||
},
|
||||
provider: {
|
||||
name: 'base-provider',
|
||||
type: SCThingType.Organization,
|
||||
uid: '540862f3-ea30-5b8f-8678-56b4dc217141',
|
||||
},
|
||||
},
|
||||
],
|
||||
origin: {
|
||||
indexed: '1970-01-01T00:00:00.000Z',
|
||||
name: 'dish-connector',
|
||||
type: SCThingOriginType.Remote,
|
||||
},
|
||||
translations: {
|
||||
de: {
|
||||
characteristics: [{name: 'de-characteristic0'}, {name: 'de-characteristic1'}],
|
||||
name: 'de-dish-name',
|
||||
},
|
||||
},
|
||||
type: SCThingType.Dish,
|
||||
uid: '540862f3-ea30-5b8f-8678-56b4dc217140',
|
||||
};
|
||||
|
||||
const setting: SCSetting = {
|
||||
categories: ['profile'],
|
||||
defaultValue: 'student',
|
||||
description: 'base-description',
|
||||
inputType: SCSettingInputType.SingleChoice,
|
||||
name: 'group',
|
||||
order: 1,
|
||||
origin: {
|
||||
indexed: '2018-11-11T14:30:00Z',
|
||||
name: 'Dummy',
|
||||
type: SCThingOriginType.Remote,
|
||||
},
|
||||
type: SCThingType.Setting,
|
||||
uid: '2c97aa36-4aa2-43de-bc5d-a2b2cb3a530e',
|
||||
values: ['student', 'employee', true, 42],
|
||||
};
|
||||
import {SCThingRemoteOrigin} from '../src/index.js';
|
||||
import {SCDishMeta} from '../src/index.js';
|
||||
import {SCThingTranslator} from '../src/index.js';
|
||||
import {dish} from './dummy/dish.js';
|
||||
import {setting} from './dummy/setting.js';
|
||||
|
||||
const translator = new SCThingTranslator('de');
|
||||
const translatorEN = new SCThingTranslator('en');
|
||||
@@ -111,242 +29,207 @@ const translatorWithFallback = new SCThingTranslator('tt');
|
||||
const translatedThingDE = translator.translate(dish);
|
||||
const translatedThingFallback = translatorWithFallback.translate(dish);
|
||||
|
||||
@suite(timeout(10000), slow(5000))
|
||||
export class TranslationSpecInplace {
|
||||
@test
|
||||
public directEnumSingleValue() {
|
||||
expect(translator.translatedAccess(setting).inputType()).to.equal('einfache Auswahl');
|
||||
}
|
||||
describe('Translator', function () {
|
||||
this.timeout(10_000);
|
||||
this.slow(5000);
|
||||
|
||||
@test
|
||||
public directStringLiteralType() {
|
||||
expect(translator.translatedAccess(dish).type()).to.equal('Essen');
|
||||
expect(translatedThingDE.type).to.equal('Essen');
|
||||
}
|
||||
|
||||
@test
|
||||
public directStringProperty() {
|
||||
expect(translator.translatedAccess(dish).name()).to.equal('de-dish-name');
|
||||
expect(translatedThingDE.name).to.equal('de-dish-name');
|
||||
}
|
||||
|
||||
@test
|
||||
public directArrayOfString() {
|
||||
expect(translator.translatedAccess(dish).characteristics()).to.deep.equal([
|
||||
{name: 'de-characteristic0'},
|
||||
{name: 'de-characteristic1'},
|
||||
]);
|
||||
expect(translatedThingDE.characteristics).to.deep.equal([
|
||||
{name: 'de-characteristic0'},
|
||||
{name: 'de-characteristic1'},
|
||||
]);
|
||||
}
|
||||
|
||||
@test
|
||||
public directArrayOfStringSubscript() {
|
||||
expect(translator.translatedAccess(dish).characteristics[1]()).to.deep.equal({
|
||||
name: 'de-characteristic1',
|
||||
describe('direct', function () {
|
||||
it('should translate enum single value', function () {
|
||||
expect(translator.translatedAccess(setting).inputType).to.equal('einfache Auswahl');
|
||||
});
|
||||
expect(translatedThingDE.characteristics![1]).to.deep.equal({name: 'de-characteristic1'});
|
||||
}
|
||||
|
||||
@test
|
||||
public directMetaArrayOfString() {
|
||||
expect(translator.translatedAccess(dish).categories()).to.deep.equal(['Hauptgericht', 'Nachtisch']);
|
||||
expect(translatedThingDE.categories).to.deep.equal(['Hauptgericht', 'Nachtisch']);
|
||||
}
|
||||
|
||||
@test
|
||||
public directMetaArrayOfStringSubscript() {
|
||||
expect(translator.translatedAccess(dish).categories[1]()).to.equal('Nachtisch');
|
||||
expect(translatedThingDE.categories[1]).to.equal('Nachtisch');
|
||||
}
|
||||
|
||||
@test
|
||||
public nestedStringLiteralType() {
|
||||
expect(translator.translatedAccess(dish).offers[0].inPlace.type()).to.equal('Gebäude');
|
||||
expect(translatedThingDE.offers![0].inPlace!.type).to.equal('Gebäude');
|
||||
}
|
||||
|
||||
@test
|
||||
public nestedStringProperty() {
|
||||
expect(translator.translatedAccess(dish).offers[0].inPlace.name()).to.equal('de-space-name');
|
||||
expect(translatedThingDE.offers![0].inPlace!.name).to.equal('de-space-name');
|
||||
}
|
||||
|
||||
@test
|
||||
public nestedMetaArrayOfString() {
|
||||
expect(translator.translatedAccess(dish).offers[0].inPlace.categories()).to.deep.equal([
|
||||
'Büro',
|
||||
'Bildung',
|
||||
]);
|
||||
expect(translatedThingDE.offers![0].inPlace!.categories).to.deep.equal(['Büro', 'Bildung']);
|
||||
}
|
||||
|
||||
@test
|
||||
public nestedMetaArrayOfStringSubscript() {
|
||||
expect(translator.translatedAccess(dish).offers[0].inPlace.categories[1]()).to.equal('Bildung');
|
||||
expect(translatedThingDE.offers![0].inPlace!.categories[1]).to.equal('Bildung');
|
||||
}
|
||||
|
||||
@test
|
||||
public directStringLiteralTypeFallback() {
|
||||
expect(translatorWithFallback.translatedAccess(dish).type()).to.equal('dish');
|
||||
expect(translatedThingFallback.type).to.equal('dish');
|
||||
}
|
||||
|
||||
@test
|
||||
public directStringPropertyFallback() {
|
||||
expect(translatorWithFallback.translatedAccess(dish).name()).to.equal('base-dish-name');
|
||||
expect(translatedThingFallback.name).to.equal('base-dish-name');
|
||||
}
|
||||
|
||||
@test
|
||||
public directArrayOfStringSubscriptFallback() {
|
||||
expect(translatorWithFallback.translatedAccess(dish).characteristics[1]()).to.deep.equal({
|
||||
name: 'base-characteristic1',
|
||||
it('should translate string literal type', function () {
|
||||
expect(translator.translatedAccess(dish).type).to.equal('Essen');
|
||||
expect(translatedThingDE.type).to.equal('Essen');
|
||||
});
|
||||
expect(translatedThingFallback.characteristics![1]).to.deep.equal({name: 'base-characteristic1'});
|
||||
}
|
||||
|
||||
@test
|
||||
public directMetaArrayOfStringFallback() {
|
||||
expect(translatorWithFallback.translatedAccess(dish).categories()).to.deep.equal([
|
||||
'main dish',
|
||||
'dessert',
|
||||
]);
|
||||
expect(translatedThingFallback.categories).to.deep.equal(['main dish', 'dessert']);
|
||||
}
|
||||
it('should translate string property', function () {
|
||||
expect(translator.translatedAccess(dish).name).to.equal('de-dish-name');
|
||||
expect(translatedThingDE.name).to.equal('de-dish-name');
|
||||
});
|
||||
|
||||
@test
|
||||
public directMetaArrayOfStringSubscriptFallback() {
|
||||
expect(translatorWithFallback.translatedAccess(dish).categories[1]()).to.equal('dessert');
|
||||
expect(translatedThingFallback.categories[1]).to.equal('dessert');
|
||||
}
|
||||
it('should translate array of strings', function () {
|
||||
expect(translator.translatedAccess(dish).characteristics).to.deep.equal([
|
||||
{name: 'de-characteristic0'},
|
||||
{name: 'de-characteristic1'},
|
||||
]);
|
||||
expect(translatedThingDE.characteristics).to.deep.equal([
|
||||
{name: 'de-characteristic0'},
|
||||
{name: 'de-characteristic1'},
|
||||
]);
|
||||
});
|
||||
|
||||
@test
|
||||
public nestedStringLiteralTypeFallback() {
|
||||
expect(translatorWithFallback.translatedAccess(dish).offers[0].inPlace.type()).to.equal('building');
|
||||
expect(translatedThingFallback.offers![0].inPlace!.type).to.equal('building');
|
||||
}
|
||||
it('should translate array of strings subscript', function () {
|
||||
expect(translator.translatedAccess(dish).characteristics?.[1]).to.deep.equal({
|
||||
name: 'de-characteristic1',
|
||||
});
|
||||
expect(translatedThingDE.characteristics![1]).to.deep.equal({name: 'de-characteristic1'});
|
||||
});
|
||||
|
||||
@test
|
||||
public nestedStringPropertyFallback() {
|
||||
expect(translatorWithFallback.translatedAccess(dish).offers[0].inPlace.name()).to.equal(
|
||||
'base-space-name',
|
||||
);
|
||||
expect(translatedThingFallback.offers![0].inPlace!.name).to.equal('base-space-name');
|
||||
}
|
||||
it('should translate meta array of string', function () {
|
||||
expect(translator.translatedAccess(dish).categories).to.deep.equal(['Hauptgericht', 'Nachtisch']);
|
||||
expect(translatedThingDE.categories).to.deep.equal(['Hauptgericht', 'Nachtisch']);
|
||||
});
|
||||
|
||||
@test
|
||||
public nestedMetaArrayOfStringFallback() {
|
||||
expect(translatorWithFallback.translatedAccess(dish).offers[0].inPlace.categories()).to.deep.equal([
|
||||
'office',
|
||||
'education',
|
||||
]);
|
||||
expect(translatedThingFallback.offers![0].inPlace!.categories).to.deep.equal(['office', 'education']);
|
||||
}
|
||||
it('should translate meta array of strings subscript', function () {
|
||||
expect(translator.translatedAccess(dish).categories[1]).to.equal('Nachtisch');
|
||||
expect(translatedThingDE.categories[1]).to.equal('Nachtisch');
|
||||
});
|
||||
});
|
||||
|
||||
@test
|
||||
public nestedMetaArrayOfStringSubscriptFallback() {
|
||||
expect(translatorWithFallback.translatedAccess(dish).offers[0].inPlace.categories[1]()).to.equal(
|
||||
'education',
|
||||
);
|
||||
expect(translatedThingFallback.offers![0].inPlace!.categories[1]).to.equal('education');
|
||||
}
|
||||
describe('nested', function () {
|
||||
it('should translate string literal type', function () {
|
||||
expect(translator.translatedAccess(dish).offers?.[0].inPlace?.type).to.equal('Gebäude');
|
||||
expect(translatedThingDE.offers![0].inPlace!.type).to.equal('Gebäude');
|
||||
});
|
||||
|
||||
@test
|
||||
public directStringLiteralTypeUndefined() {
|
||||
const undefinedThing = eval('(x) => undefined;');
|
||||
expect(translator.translatedAccess(undefinedThing())('defaultValue')).to.equal('defaultValue');
|
||||
expect(translator.translatedAccess(dish).name('defaultValue')).to.not.equal('defaultValue');
|
||||
}
|
||||
it('should translate nested string property', function () {
|
||||
expect(translator.translatedAccess(dish).offers?.[0].inPlace?.name).to.equal('de-space-name');
|
||||
expect(translatedThingDE.offers![0].inPlace!.name).to.equal('de-space-name');
|
||||
});
|
||||
|
||||
@test
|
||||
public nestedMetaArrayOfStringSubscriptUndefined() {
|
||||
const workingTranslation = eval(
|
||||
"translator.translatedAccess(dish).offers[0].inPlace.categories[1]('printer');",
|
||||
);
|
||||
const defaultValueTranslation = eval(
|
||||
"translator.translatedAccess(dish).offers[0].inPlace.categories[1234]('printer');",
|
||||
);
|
||||
it('should translate meta array of strings', function () {
|
||||
expect(translator.translatedAccess(dish).offers?.[0].inPlace?.categories).to.deep.equal([
|
||||
'Büro',
|
||||
'Bildung',
|
||||
]);
|
||||
expect(translatedThingDE.offers![0].inPlace!.categories).to.deep.equal(['Büro', 'Bildung']);
|
||||
});
|
||||
|
||||
expect(defaultValueTranslation).to.equal('printer');
|
||||
expect(workingTranslation).to.not.equal('printer');
|
||||
}
|
||||
it('should translate meta array of strings subscript', function () {
|
||||
expect(translator.translatedAccess(dish).offers?.[0].inPlace?.categories[1]).to.equal('Bildung');
|
||||
expect(translatedThingDE.offers![0].inPlace!.categories[1]).to.equal('Bildung');
|
||||
});
|
||||
});
|
||||
|
||||
@test
|
||||
public reaccessWithChangedSourceOmitsLRUCache() {
|
||||
describe('direct (fallback)', function () {
|
||||
it('should translate string literal types', function () {
|
||||
expect(translatorWithFallback.translatedAccess(dish).type).to.equal('dish');
|
||||
expect(translatedThingFallback.type).to.equal('dish');
|
||||
});
|
||||
|
||||
it('should translate string property', function () {
|
||||
expect(translatorWithFallback.translatedAccess(dish).name).to.equal('base-dish-name');
|
||||
expect(translatedThingFallback.name).to.equal('base-dish-name');
|
||||
});
|
||||
|
||||
it('should translate array of strings subscript', function () {
|
||||
expect(translatorWithFallback.translatedAccess(dish).characteristics?.[1]).to.deep.equal({
|
||||
name: 'base-characteristic1',
|
||||
});
|
||||
expect(translatedThingFallback.characteristics![1]).to.deep.equal({name: 'base-characteristic1'});
|
||||
});
|
||||
|
||||
it('should translate meta array of strings', function () {
|
||||
expect(translatorWithFallback.translatedAccess(dish).categories).to.deep.equal([
|
||||
'main dish',
|
||||
'dessert',
|
||||
]);
|
||||
expect(translatedThingFallback.categories).to.deep.equal(['main dish', 'dessert']);
|
||||
});
|
||||
|
||||
it('should translate meta array of string subscript', function () {
|
||||
expect(translatorWithFallback.translatedAccess(dish).categories[1]).to.equal('dessert');
|
||||
expect(translatedThingFallback.categories[1]).to.equal('dessert');
|
||||
});
|
||||
});
|
||||
|
||||
describe('nested (fallback)', function () {
|
||||
it('should translate string literal type', function () {
|
||||
expect(translatorWithFallback.translatedAccess(dish).offers?.[0].inPlace?.type).to.equal('building');
|
||||
expect(translatedThingFallback.offers![0].inPlace!.type).to.equal('building');
|
||||
});
|
||||
|
||||
it('should translate string property', function () {
|
||||
expect(translatorWithFallback.translatedAccess(dish).offers?.[0].inPlace?.name).to.equal(
|
||||
'base-space-name',
|
||||
);
|
||||
expect(translatedThingFallback.offers![0].inPlace!.name).to.equal('base-space-name');
|
||||
});
|
||||
|
||||
it('should translate meta array of string', function () {
|
||||
expect(translatorWithFallback.translatedAccess(dish).offers?.[0].inPlace?.categories).to.deep.equal([
|
||||
'office',
|
||||
'education',
|
||||
]);
|
||||
expect(translatedThingFallback.offers![0].inPlace!.categories).to.deep.equal(['office', 'education']);
|
||||
});
|
||||
|
||||
it('should translate meta array of strings subscript', function () {
|
||||
expect(translatorWithFallback.translatedAccess(dish).offers?.[0].inPlace?.categories[1]).to.equal(
|
||||
'education',
|
||||
);
|
||||
expect(translatedThingFallback.offers![0].inPlace!.categories[1]).to.equal('education');
|
||||
});
|
||||
});
|
||||
|
||||
it('should omit LRU cache with changed source', function () {
|
||||
const translatorDE = new SCThingTranslator('de');
|
||||
const dishCopy = clone()(dish);
|
||||
const translatedDish = translatorDE.translatedAccess(dish);
|
||||
const distructivelyTranslatedDish = translatorDE.translate(dish);
|
||||
const destructivelyTranslatedDish = translatorDE.translate(dish);
|
||||
|
||||
(dishCopy.origin as SCThingRemoteOrigin).name = 'tranlator.spec';
|
||||
(dishCopy.origin as SCThingRemoteOrigin).name = 'translator.spec';
|
||||
expect(translatorDE.translatedAccess(dishCopy)).not.to.deep.equal(translatedDish);
|
||||
expect(translatorDE.translate(dishCopy)).not.to.equal(distructivelyTranslatedDish);
|
||||
}
|
||||
expect(translatorDE.translate(dishCopy)).not.to.equal(destructivelyTranslatedDish);
|
||||
});
|
||||
|
||||
@test
|
||||
public changingTranslatorLanguageFlushesItsLRUCache() {
|
||||
it('should flush its LRU cache with changed translator language', function () {
|
||||
const translatorDE = new SCThingTranslator('de');
|
||||
expect(translatorDE.translatedAccess(dish).name()).to.equal('de-dish-name');
|
||||
expect(translatorDE.translatedAccess(dish).name).to.equal('de-dish-name');
|
||||
expect(translatorDE.translate(dish).name).to.equal('de-dish-name');
|
||||
translatorDE.language = 'en';
|
||||
expect(translatorDE.translatedAccess(dish).name()).to.equal('base-dish-name');
|
||||
expect(translatorDE.translatedAccess(dish).name).to.equal('base-dish-name');
|
||||
expect(translatorDE.translate(dish).name).to.equal('base-dish-name');
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
public forceTranslatorLRUCacheToOverflow() {
|
||||
it('should force translator LRU cache to overflow', function () {
|
||||
const translatorDE = new SCThingTranslator('de');
|
||||
// Make sure to add more elements to the translator cache than the maximum cache capacity. See Translator.ts
|
||||
for (let i = 0; i < 201; i++) {
|
||||
const anotherDish = Object.assign({}, dish);
|
||||
anotherDish.uid = String(i);
|
||||
expect(translatorDE.translatedAccess(anotherDish).name()).to.equal('de-dish-name');
|
||||
expect(translatorDE.translatedAccess(anotherDish).name).to.equal('de-dish-name');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@suite(timeout(10000), slow(5000))
|
||||
export class MetaTranslationSpec {
|
||||
@test
|
||||
public consistencyWithMetaClass() {
|
||||
describe('MetaTranslator', function () {
|
||||
this.timeout(10_000);
|
||||
this.slow(5000);
|
||||
|
||||
it('should have consistency with meta class', function () {
|
||||
const dishMetaTranslationsDE = translator.translatedPropertyNames(dish.type);
|
||||
const dishMetaTranslationsEN = translatorEN.translatedPropertyNames(dish.type);
|
||||
expect(dishMetaTranslationsEN).to.not.deep.equal(dishMetaTranslationsDE);
|
||||
expect(dishMetaTranslationsDE).to.deep.equal(new SCDishMeta().fieldTranslations.de);
|
||||
expect(dishMetaTranslationsEN).to.deep.equal(new SCDishMeta().fieldTranslations.en);
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
public retrieveTranslatedPropertyValueType() {
|
||||
it('should retrieve translated property value type', function () {
|
||||
const dishTypeDE = translator.translatedPropertyValue(dish.type, 'type');
|
||||
const dishTypeEN = translatorEN.translatedPropertyValue(dish.type, 'type', undefined);
|
||||
const dishTypeBASE = translatorWithFallback.translatedPropertyValue(dish.type, 'type');
|
||||
expect(dishTypeDE).to.deep.equal(new SCDishMeta().fieldValueTranslations.de.type);
|
||||
expect(dishTypeEN).to.deep.equal(new SCDishMeta().fieldValueTranslations.en.type);
|
||||
expect(dishTypeBASE).to.deep.equal(new SCDishMeta().fieldValueTranslations.en.type);
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
public retrieveTranslatedPropertyValueNested() {
|
||||
it('should retrieve translated property value nested', function () {
|
||||
const dishTypeDE = translator.translatedPropertyValue(dish.type, 'categories', 'main dish');
|
||||
const dishTypeEN = translatorEN.translatedPropertyValue(dish.type, 'categories', 'main dish');
|
||||
const dishTypeBASE = translatorWithFallback.translatedPropertyValue(dish.type, 'categories', 'main dish');
|
||||
expect(dishTypeDE).to.deep.equal(new SCDishMeta().fieldValueTranslations.de.categories['main dish']);
|
||||
expect(dishTypeEN).to.deep.equal(dish.categories[0]);
|
||||
expect(dishTypeBASE).to.deep.equal(dish.categories[0]);
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
public thingWithoutMetaClass() {
|
||||
it('should translate thing without meta class', function () {
|
||||
const dishCopy = clone()(dish);
|
||||
const typeNonExistant = eval("(x) => x + 'typeNonExistant';");
|
||||
// this will assign a non existant SCThingType to dishCopy
|
||||
dishCopy.type = typeNonExistant();
|
||||
const typeNonExistent = eval("(x) => x + 'typeNonExistent';");
|
||||
// this will assign a non-existent SCThingType to dishCopy
|
||||
dishCopy.type = typeNonExistent();
|
||||
const dishMetaTranslationsDE = translator.translatedPropertyNames(dishCopy.type);
|
||||
expect(dishMetaTranslationsDE).to.be.undefined;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/*
|
||||
* Copyright (C) 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
@@ -13,35 +14,35 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {assert, Has, IsAny, IsNever, NotHas} from 'conditional-type-checks';
|
||||
import {SCThing, SCThingWithoutReferences} from '../src/things/abstract/thing.js';
|
||||
import {SCAcademicEvent, SCAcademicEventWithoutReferences} from '../src/things/academic-event.js';
|
||||
import {SCArticle, SCArticleWithoutReferences} from '../src/things/article.js';
|
||||
import {SCAssessment, SCAssessmentWithoutReferences} from '../src/things/assessment.js';
|
||||
import {SCBook, SCBookWithoutReferences} from '../src/things/book.js';
|
||||
import {SCBuilding, SCBuildingWithoutReferences} from '../src/things/building.js';
|
||||
import {SCCatalog, SCCatalogWithoutReferences} from '../src/things/catalog.js';
|
||||
import {SCContactPoint, SCContactPointWithoutReferences} from '../src/things/contact-point.js';
|
||||
import {SCCourseOfStudy, SCCourseOfStudyWithoutReferences} from '../src/things/course-of-study.js';
|
||||
import {SCDateSeries, SCDateSeriesWithoutReferences} from '../src/things/date-series.js';
|
||||
import {SCDiff, SCDiffWithoutReferences} from '../src/things/diff.js';
|
||||
import {SCDish, SCDishWithoutReferences} from '../src/things/dish.js';
|
||||
import {SCFavorite, SCFavoriteWithoutReferences} from '../src/things/favorite.js';
|
||||
import {SCFloor, SCFloorWithoutReferences} from '../src/things/floor.js';
|
||||
import {SCMessage, SCMessageWithoutReferences} from '../src/things/message.js';
|
||||
import {SCOrganization, SCOrganizationWithoutReferences} from '../src/things/organization.js';
|
||||
import {SCPerson, SCPersonWithoutReferences} from '../src/things/person.js';
|
||||
import {SCPointOfInterest, SCPointOfInterestWithoutReferences} from '../src/things/point-of-interest.js';
|
||||
import {SCRoom, SCRoomWithoutReferences} from '../src/things/room.js';
|
||||
import {SCSemester, SCSemesterWithoutReferences} from '../src/things/semester.js';
|
||||
import {SCSetting, SCSettingWithoutReferences} from '../src/things/setting.js';
|
||||
import {SCSportCourse, SCSportCourseWithoutReferences} from '../src/things/sport-course.js';
|
||||
import {SCStudyModule, SCStudyModuleWithoutReferences} from '../src/things/study-module.js';
|
||||
import {SCTicket, SCTicketWithoutReferences} from '../src/things/ticket.js';
|
||||
import {SCToDo, SCToDoWithoutReferences} from '../src/things/todo.js';
|
||||
import {SCTour, SCTourWithoutReferences} from '../src/things/tour.js';
|
||||
import {SCVideo, SCVideoWithoutReferences} from '../src/things/video.js';
|
||||
import {SCPeriodical, SCPeriodicalWithoutReferences} from '../src/things/periodical.js';
|
||||
import {SCPublicationEvent, SCPublicationEventWithoutReferences} from '../src/things/publication-event.js';
|
||||
import {SCThing, SCThingWithoutReferences} from '../src/index.js';
|
||||
import {SCAcademicEvent, SCAcademicEventWithoutReferences} from '../src/index.js';
|
||||
import {SCArticle, SCArticleWithoutReferences} from '../src/index.js';
|
||||
import {SCAssessment, SCAssessmentWithoutReferences} from '../src/index.js';
|
||||
import {SCBook, SCBookWithoutReferences} from '../src/index.js';
|
||||
import {SCBuilding, SCBuildingWithoutReferences} from '../src/index.js';
|
||||
import {SCCatalog, SCCatalogWithoutReferences} from '../src/index.js';
|
||||
import {SCContactPoint, SCContactPointWithoutReferences} from '../src/index.js';
|
||||
import {SCCourseOfStudy, SCCourseOfStudyWithoutReferences} from '../src/index.js';
|
||||
import {SCDateSeries, SCDateSeriesWithoutReferences} from '../src/index.js';
|
||||
import {SCDiff, SCDiffWithoutReferences} from '../src/index.js';
|
||||
import {SCDish, SCDishWithoutReferences} from '../src/index.js';
|
||||
import {SCFavorite, SCFavoriteWithoutReferences} from '../src/index.js';
|
||||
import {SCFloor, SCFloorWithoutReferences} from '../src/index.js';
|
||||
import {SCMessage, SCMessageWithoutReferences} from '../src/index.js';
|
||||
import {SCOrganization, SCOrganizationWithoutReferences} from '../src/index.js';
|
||||
import {SCPerson, SCPersonWithoutReferences} from '../src/index.js';
|
||||
import {SCPointOfInterest, SCPointOfInterestWithoutReferences} from '../src/index.js';
|
||||
import {SCRoom, SCRoomWithoutReferences} from '../src/index.js';
|
||||
import {SCSemester, SCSemesterWithoutReferences} from '../src/index.js';
|
||||
import {SCSetting, SCSettingWithoutReferences} from '../src/index.js';
|
||||
import {SCSportCourse, SCSportCourseWithoutReferences} from '../src/index.js';
|
||||
import {SCStudyModule, SCStudyModuleWithoutReferences} from '../src/index.js';
|
||||
import {SCTicket, SCTicketWithoutReferences} from '../src/index.js';
|
||||
import {SCToDo, SCToDoWithoutReferences} from '../src/index.js';
|
||||
import {SCTour, SCTourWithoutReferences} from '../src/index.js';
|
||||
import {SCVideo, SCVideoWithoutReferences} from '../src/index.js';
|
||||
import {SCPeriodical, SCPeriodicalWithoutReferences} from '../src/index.js';
|
||||
import {SCPublicationEvent, SCPublicationEventWithoutReferences} from '../src/index.js';
|
||||
|
||||
/**
|
||||
* Check if E extends T
|
||||
|
||||
@@ -10,34 +10,33 @@
|
||||
"types": "./lib/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "tsup --dts",
|
||||
"format": "prettier .",
|
||||
"format:fix": "prettier --write .",
|
||||
"format": "prettier . --ignore-path ../../.gitignore",
|
||||
"format:fix": "prettier --write . --ignore-path ../../.gitignore",
|
||||
"lint": "eslint --ext .ts src/",
|
||||
"lint:fix": "eslint --fix --ext .ts src/",
|
||||
"test": "nyc mocha 'test/**/*.spec.ts'"
|
||||
"test": "c8 mocha"
|
||||
},
|
||||
"dependencies": {
|
||||
"@openstapps/collection-utils": "workspace:*",
|
||||
"@openstapps/logger": "workspace:*",
|
||||
"glob": "10.2.1",
|
||||
"typescript": "4.8.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@openstapps/eslint-config": "workspace:*",
|
||||
"@openstapps/nyc-config": "workspace:*",
|
||||
"@openstapps/prettier-config": "workspace:*",
|
||||
"@openstapps/tsconfig": "workspace:*",
|
||||
"@testdeck/mocha": "0.3.3",
|
||||
"@types/chai": "4.3.4",
|
||||
"@types/fs-extra": "9.0.13",
|
||||
"@types/mocha": "10.0.1",
|
||||
"@types/node": "18.15.3",
|
||||
"c8": "7.13.0",
|
||||
"chai": "4.3.7",
|
||||
"mocha": "10.2.0",
|
||||
"nock": "13.3.0",
|
||||
"ts-node": "10.9.1",
|
||||
"tsup": "6.7.0"
|
||||
},
|
||||
"tsup": {
|
||||
"entry": [
|
||||
"src/app.ts",
|
||||
"src/index.ts"
|
||||
],
|
||||
"sourcemap": true,
|
||||
@@ -54,8 +53,5 @@
|
||||
"eslintIgnore": [
|
||||
"resources",
|
||||
"openapi"
|
||||
],
|
||||
"nyc": {
|
||||
"extends": "@openstapps/nyc-config"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import * as ts from 'typescript';
|
||||
import ts from 'typescript';
|
||||
import {cleanupEmpty} from './util.js';
|
||||
import {LightweightComment} from './types/lightweight-comment.js';
|
||||
|
||||
@@ -33,7 +33,7 @@ export function extractComment(node: ts.Node): LightweightComment | undefined {
|
||||
? undefined
|
||||
: cleanupEmpty({
|
||||
shortSummary: comment?.[0],
|
||||
description: comment?.[comment.length - 1],
|
||||
description: comment?.slice(1).join('\n\n'),
|
||||
tags: jsDocument?.tags?.map(tag =>
|
||||
cleanupEmpty({
|
||||
name: tag.tagName?.escapedText ?? 'UNRESOLVED_NAME',
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import ts from 'typescript';
|
||||
import {cleanupEmpty, mapNotNil, rejectNil, expandPathToFilesSync} from './util.js';
|
||||
import {cleanupEmpty, expandPathToFilesSync, mapNotNil, rejectNil} from './util.js';
|
||||
import {
|
||||
extractComment,
|
||||
filterChildrenTo,
|
||||
@@ -77,7 +77,7 @@ class LightweightDefinitionBuilder {
|
||||
constructor(sourcePath: string | string[], readonly includeComments: boolean) {
|
||||
const rootNames = Array.isArray(sourcePath)
|
||||
? sourcePath
|
||||
: expandPathToFilesSync(path.resolve(sourcePath), file => file.endsWith('ts'));
|
||||
: expandPathToFilesSync(path.resolve(sourcePath), it => it.endsWith('.ts'));
|
||||
|
||||
this.program = ts.createProgram({
|
||||
rootNames: rootNames,
|
||||
@@ -121,7 +121,7 @@ class LightweightDefinitionBuilder {
|
||||
classLike: ts.ClassDeclaration | ts.InterfaceDeclaration,
|
||||
): LightweightClassDefinition {
|
||||
const heritages = mapValues(
|
||||
groupBy([...classLike.heritageClauses!], it => it.token.toString()),
|
||||
groupBy([...(classLike.heritageClauses || [])], it => it.token.toString()),
|
||||
heritages => heritages.flatMap(it => it.types),
|
||||
);
|
||||
|
||||
@@ -162,23 +162,25 @@ class LightweightDefinitionBuilder {
|
||||
|
||||
collectProperties(
|
||||
members: ts.NodeArray<ts.ClassElement | ts.TypeElement>,
|
||||
): Record<string, LightweightProperty> {
|
||||
return keyBy(
|
||||
filterNodeTo(members as ts.NodeArray<ts.ClassElement | ts.TypeElement>, isProperty).map(property =>
|
||||
cleanupEmpty({
|
||||
comment: this.includeComments ? extractComment(property) : undefined,
|
||||
name: resolvePropertyName(property.name) ?? property.getText(),
|
||||
type: this.lightweightTypeAtNode(property),
|
||||
properties: this.collectProperties((property.type as ts.TypeLiteralNode)?.members),
|
||||
optional: ts.isPropertyDeclaration(property)
|
||||
? property.questionToken === undefined
|
||||
? undefined
|
||||
: true
|
||||
: undefined,
|
||||
}),
|
||||
),
|
||||
it => it.name,
|
||||
);
|
||||
): Record<string, LightweightProperty> | undefined {
|
||||
return members
|
||||
? keyBy(
|
||||
filterNodeTo(members as ts.NodeArray<ts.ClassElement | ts.TypeElement>, isProperty).map(property =>
|
||||
cleanupEmpty({
|
||||
comment: this.includeComments ? extractComment(property) : undefined,
|
||||
name: resolvePropertyName(property.name) ?? property.getText(),
|
||||
type: this.lightweightTypeAtNode(property),
|
||||
properties: this.collectProperties((property.type as ts.TypeLiteralNode)?.members),
|
||||
optional: ts.isPropertyDeclaration(property)
|
||||
? property.questionToken === undefined
|
||||
? undefined
|
||||
: true
|
||||
: undefined,
|
||||
}),
|
||||
),
|
||||
it => it.name,
|
||||
)
|
||||
: undefined;
|
||||
}
|
||||
|
||||
private lightweightTypeAtNode(node: ts.Node): LightweightType {
|
||||
|
||||
@@ -12,14 +12,14 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
export * from './easy-ast.js'
|
||||
export * from './ast-util.js'
|
||||
export * from './easy-ast.js';
|
||||
export * from './ast-util.js';
|
||||
|
||||
export * from './types/lightweight-alias-definition.js'
|
||||
export * from './types/lightweight-class-definition.js'
|
||||
export * from './types/lightweight-comment.js'
|
||||
export * from './types/lightweight-definition.js'
|
||||
export * from './types/lightweight-definition-kind.js'
|
||||
export * from './types/lightweight-project.js'
|
||||
export * from './types/lightweight-property.js'
|
||||
export * from './types/lightweight-type.js'
|
||||
export * from './types/lightweight-alias-definition.js';
|
||||
export * from './types/lightweight-class-definition.js';
|
||||
export * from './types/lightweight-comment.js';
|
||||
export * from './types/lightweight-definition.js';
|
||||
export * from './types/lightweight-definition-kind.js';
|
||||
export * from './types/lightweight-project.js';
|
||||
export * from './types/lightweight-property.js';
|
||||
export * from './types/lightweight-type.js';
|
||||
|
||||
@@ -12,15 +12,36 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import path from "path";
|
||||
import {readdirSync, statSync} from "fs";
|
||||
import {readdirSync, statSync} from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
/**
|
||||
* Expand a path to a list of all files deeply contained in it
|
||||
*/
|
||||
export function expandPathToFilesSync(sourcePath: string, accept: (fileName: string) => boolean): string[] {
|
||||
const fullPath = path.resolve(sourcePath);
|
||||
const directory = statSync(fullPath);
|
||||
|
||||
return directory.isDirectory()
|
||||
? readdirSync(fullPath).flatMap(fragment =>
|
||||
expandPathToFilesSync(path.resolve(sourcePath, fragment), accept),
|
||||
)
|
||||
: [fullPath].filter(accept);
|
||||
}
|
||||
|
||||
/**
|
||||
* Take a Windows path and make a Unix path out of it
|
||||
*/
|
||||
export function toUnixPath(pathString: string): string {
|
||||
return pathString.replaceAll(path.sep, path.posix.sep);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters only defined elements
|
||||
*/
|
||||
export function rejectNil<T>(array: Array<T | undefined | null>): T[] {
|
||||
// eslint-disable-next-line unicorn/no-null
|
||||
return array.filter(it => it == null) as T[];
|
||||
return array.filter(it => it != null) as T[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -45,17 +66,3 @@ export function cleanupEmpty<T extends object>(object: T): T {
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand a path to a list of all files deeply contained in it
|
||||
*/
|
||||
export function expandPathToFilesSync(sourcePath: string, accept: (fileName: string) => boolean): string[] {
|
||||
const fullPath = path.resolve(sourcePath);
|
||||
const directory = statSync(fullPath);
|
||||
|
||||
return directory.isDirectory()
|
||||
? readdirSync(fullPath).flatMap(fragment =>
|
||||
expandPathToFilesSync(path.resolve(sourcePath, fragment), accept),
|
||||
)
|
||||
: [fullPath].filter(accept);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {LightweightFile} from '../../src/easy-ast/types/lightweight-project.js';
|
||||
import {LightweightFile} from '../src/index.js';
|
||||
|
||||
export interface EasyAstSpecType {
|
||||
testName: string;
|
||||
|
||||
48
packages/easy-ast/test/index.spec.ts
Normal file
48
packages/easy-ast/test/index.spec.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2021 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {lightweightProjectFromPath} from '../src/index.js';
|
||||
import {expect} from 'chai';
|
||||
import {expandPathToFilesSync, toUnixPath} from '../src/util.js';
|
||||
import type {EasyAstSpecType} from './easy-ast-spec-type.js';
|
||||
|
||||
const projectPath = './test/project';
|
||||
|
||||
const tests = await Promise.all(
|
||||
expandPathToFilesSync(projectPath, file => file.endsWith('ast-test.ts')).map(async it => ({
|
||||
path: toUnixPath(it),
|
||||
config: await import(`file://${it}`).then(it => it.testConfig as EasyAstSpecType),
|
||||
})),
|
||||
);
|
||||
|
||||
describe('Easy AST', async function () {
|
||||
it('should build the project', function () {
|
||||
const project = lightweightProjectFromPath(projectPath, true);
|
||||
expect(Object.keys(project).length).to.equal(tests.length);
|
||||
});
|
||||
|
||||
const project = lightweightProjectFromPath(projectPath, true);
|
||||
|
||||
for (const {path, config} of tests) {
|
||||
it(config.testName, function () {
|
||||
const projectAtPath = project[path];
|
||||
expect(projectAtPath).not.to.be.undefined;
|
||||
for (const key in projectAtPath) {
|
||||
if (key.startsWith('$')) delete projectAtPath[key];
|
||||
}
|
||||
|
||||
expect(projectAtPath).to.be.deep.equal(config.expected);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {expandPathToFilesSync, toUnixPath} from '../src/util.js';
|
||||
import {EasyAstSpecType} from './easy-ast-spec-type.js';
|
||||
import {lightweightProjectFromPath} from '../src/easy-ast.js';
|
||||
import {expect} from 'chai';
|
||||
|
||||
describe('Easy AST', async () => {
|
||||
const project = lightweightProjectFromPath('./test/easy-ast', true);
|
||||
for (const file of expandPathToFilesSync('./test/easy-ast', file => file.endsWith('ast-test.ts'))) {
|
||||
try {
|
||||
const test = (await import(file))['testConfig'] as EasyAstSpecType;
|
||||
|
||||
it(test.testName, () => {
|
||||
expect(omitBy(project[toUnixPath(file)], (_value, key) => key.startsWith('$'))).to.be.deep.equal(
|
||||
test.expected,
|
||||
);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -13,11 +13,13 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {EasyAstSpecType} from './easy-ast-spec-type.js';
|
||||
import {LightweightDefinitionKind} from '../../src/easy-ast/types/lightweight-definition-kind.js';
|
||||
import {EasyAstSpecType} from '../easy-ast-spec-type.js';
|
||||
import {LightweightDefinitionKind} from '../../src/index.js';
|
||||
|
||||
// @ts-expect-error unused type
|
||||
type TestTypeAlias = number | string;
|
||||
|
||||
// @ts-expect-error unused type
|
||||
enum TestEnum {
|
||||
Foo,
|
||||
Bar,
|
||||
@@ -13,14 +13,18 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {EasyAstSpecType} from './easy-ast-spec-type.js';
|
||||
import {LightweightDefinitionKind} from '../../src/easy-ast/types/lightweight-definition-kind.js';
|
||||
import {EasyAstSpecType} from '../easy-ast-spec-type.js';
|
||||
import {LightweightDefinitionKind} from '../../src/index.js';
|
||||
|
||||
interface Random {}
|
||||
|
||||
// @ts-expect-error unused type
|
||||
type TestArrayGeneric = Array<string>;
|
||||
// @ts-expect-error unused type
|
||||
type TestArrayLiteral = number[];
|
||||
// @ts-expect-error unused type
|
||||
type TestArrayReferenceGeneric = Array<Random>;
|
||||
// @ts-expect-error unused type
|
||||
type TestArrayReferenceLiteral = Random[];
|
||||
|
||||
export const testConfig: EasyAstSpecType = {
|
||||
@@ -13,13 +13,15 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {EasyAstSpecType} from './easy-ast-spec-type.js';
|
||||
import {LightweightDefinitionKind} from '../../src/easy-ast/types/lightweight-definition-kind.js';
|
||||
import {EasyAstSpecType} from '../easy-ast-spec-type.js';
|
||||
import {LightweightDefinitionKind} from '../../src/index.js';
|
||||
|
||||
// @ts-expect-error unused type
|
||||
interface TestInterface {
|
||||
foo: number;
|
||||
}
|
||||
|
||||
// @ts-expect-error unused type
|
||||
class TestClass {
|
||||
bar: string = 'test';
|
||||
}
|
||||
@@ -13,8 +13,8 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {EasyAstSpecType} from './easy-ast-spec-type.js';
|
||||
import {LightweightDefinitionKind} from '../../src/easy-ast/types/lightweight-definition-kind.js';
|
||||
import {EasyAstSpecType} from '../easy-ast-spec-type.js';
|
||||
import {LightweightDefinitionKind} from '../../src/index.js';
|
||||
|
||||
/**
|
||||
* Class comment
|
||||
@@ -25,6 +25,7 @@ import {LightweightDefinitionKind} from '../../src/easy-ast/types/lightweight-de
|
||||
*
|
||||
* @classTag classParameter1 classParameter2
|
||||
*/
|
||||
// @ts-expect-error unused type
|
||||
interface TestInterface {
|
||||
/**
|
||||
* Property comment
|
||||
@@ -47,6 +48,7 @@ interface TestInterface {
|
||||
*
|
||||
* @classTag classParameter1 classParameter2
|
||||
*/
|
||||
// @ts-expect-error unused type
|
||||
class TestClass {
|
||||
/**
|
||||
* Property comment
|
||||
@@ -69,6 +71,7 @@ class TestClass {
|
||||
*
|
||||
* @enumTag enumParameter1
|
||||
*/
|
||||
// @ts-expect-error unused type
|
||||
enum TestAlias {}
|
||||
|
||||
export const testConfig: EasyAstSpecType = {
|
||||
@@ -13,13 +13,14 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {EasyAstSpecType} from './easy-ast-spec-type.js';
|
||||
import {LightweightDefinitionKind} from '../../src/easy-ast/types/lightweight-definition-kind.js';
|
||||
import {EasyAstSpecType} from '../easy-ast-spec-type.js';
|
||||
import {LightweightDefinitionKind} from '../../src/index.js';
|
||||
|
||||
interface Test1<T = number> {
|
||||
foo: T;
|
||||
}
|
||||
|
||||
// @ts-expect-error unused type
|
||||
interface Test2 {
|
||||
bar: Test1;
|
||||
}
|
||||
@@ -13,14 +13,16 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {EasyAstSpecType} from './easy-ast-spec-type.js';
|
||||
import {LightweightDefinitionKind} from '../../src/easy-ast/types/lightweight-definition-kind.js';
|
||||
import {EasyAstSpecType} from '../easy-ast-spec-type.js';
|
||||
import {LightweightDefinitionKind} from '../../src/index.js';
|
||||
|
||||
// @ts-expect-error unused type
|
||||
enum TestAuto {
|
||||
Foo,
|
||||
Bar,
|
||||
}
|
||||
|
||||
// @ts-expect-error unused type
|
||||
enum TestSpecified {
|
||||
YES = 'yes',
|
||||
NO = 'no',
|
||||
@@ -13,11 +13,12 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {EasyAstSpecType} from './easy-ast-spec-type.js';
|
||||
import {LightweightDefinitionKind} from '../../src/easy-ast/types/lightweight-definition-kind.js';
|
||||
import {EasyAstSpecType} from '../easy-ast-spec-type.js';
|
||||
import {LightweightDefinitionKind} from '../../src/index.js';
|
||||
|
||||
interface $Random {}
|
||||
|
||||
// @ts-expect-error unused type
|
||||
interface Generics {
|
||||
baz: Foo<number, $Random>;
|
||||
}
|
||||
@@ -13,15 +13,17 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {EasyAstSpecType} from './easy-ast-spec-type.js';
|
||||
import {LightweightDefinitionKind} from '../../src/easy-ast/types/lightweight-definition-kind.js';
|
||||
import {EasyAstSpecType} from '../easy-ast-spec-type.js';
|
||||
import {LightweightDefinitionKind} from '../../src/index.js';
|
||||
|
||||
interface $Random {}
|
||||
|
||||
// @ts-expect-error unused
|
||||
interface IndexSignatureObject {
|
||||
[key: string]: $Random;
|
||||
}
|
||||
|
||||
// @ts-expect-error unused
|
||||
interface IndexSignaturePrimitive {
|
||||
[key: string]: number;
|
||||
}
|
||||
@@ -13,8 +13,8 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {EasyAstSpecType} from './easy-ast-spec-type.js';
|
||||
import {LightweightDefinitionKind} from '../../src/easy-ast/types/lightweight-definition-kind.js';
|
||||
import {EasyAstSpecType} from '../easy-ast-spec-type.js';
|
||||
import {LightweightDefinitionKind} from '../../src/index.js';
|
||||
|
||||
interface $BaseInterface<T> {
|
||||
foo: T;
|
||||
@@ -26,6 +26,7 @@ interface $BaseInterface2 {
|
||||
|
||||
class $BaseClass {}
|
||||
|
||||
// @ts-expect-error unused
|
||||
class InheritingClass extends $BaseClass implements $BaseInterface<number>, $BaseInterface2 {
|
||||
bar: string = '';
|
||||
|
||||
@@ -13,9 +13,10 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {EasyAstSpecType} from './easy-ast-spec-type.js';
|
||||
import {LightweightDefinitionKind} from '../../src/easy-ast/types/lightweight-definition-kind.js';
|
||||
import {EasyAstSpecType} from '../easy-ast-spec-type.js';
|
||||
import {LightweightDefinitionKind} from '../../src/index.js';
|
||||
|
||||
// @ts-expect-error unused
|
||||
interface NestedObject {
|
||||
nested: {
|
||||
deeplyNested: {
|
||||
@@ -13,9 +13,10 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {EasyAstSpecType} from './easy-ast-spec-type.js';
|
||||
import {LightweightDefinitionKind} from '../../src/easy-ast/types/lightweight-definition-kind.js';
|
||||
import {EasyAstSpecType} from '../easy-ast-spec-type.js';
|
||||
import {LightweightDefinitionKind} from '../../src/index.js';
|
||||
|
||||
// @ts-expect-error unused
|
||||
interface Test {
|
||||
number_type: number;
|
||||
string_type: string;
|
||||
@@ -13,9 +13,10 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {EasyAstSpecType} from './easy-ast-spec-type.js';
|
||||
import {LightweightDefinitionKind} from '../../src/easy-ast/types/lightweight-definition-kind.js';
|
||||
import {EasyAstSpecType} from '../easy-ast-spec-type.js';
|
||||
import {LightweightDefinitionKind} from '../../src/index.js';
|
||||
|
||||
// @ts-expect-error unused
|
||||
interface Foo<T extends Bar<string>> {
|
||||
bar: T;
|
||||
}
|
||||
@@ -13,11 +13,11 @@
|
||||
"author": "Thea Schöbl <dev@theaninova.de>",
|
||||
"scripts": {
|
||||
"build": "rimraf lib && tsc",
|
||||
"format": "prettier .",
|
||||
"format:fix": "prettier --write .",
|
||||
"format": "prettier . --ignore-path ../../.gitignore",
|
||||
"format:fix": "prettier --write . --ignore-path ../../.gitignore",
|
||||
"lint": "eslint -c .eslintrc --ignore-path .eslintignore --ext .ts src/ test/",
|
||||
"lint:fix": "eslint --fix -c .eslintrc --ignore-path .eslintignore --ext .ts src/ test/",
|
||||
"test": "mocha --require ts-node/register test/*.spec.ts"
|
||||
"test": "c8 mocha"
|
||||
},
|
||||
"dependencies": {
|
||||
"@elastic/elasticsearch": "8.4.0",
|
||||
@@ -38,9 +38,10 @@
|
||||
"@types/rimraf": "3.0.2",
|
||||
"chai": "4.3.7",
|
||||
"mocha": "10.2.0",
|
||||
"c8": "7.13.0",
|
||||
"nock": "13.3.0",
|
||||
"rimraf": "5.0.0",
|
||||
"ts-node": "10.9.1",
|
||||
"rimraf": "5.0.0"
|
||||
},
|
||||
"prettier": "@openstapps/prettier-config"
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@ import {mkdirSync, readFileSync, writeFileSync} from 'fs';
|
||||
import got from 'got';
|
||||
import path from 'path';
|
||||
import {exit} from 'process';
|
||||
import {generateTemplate} from './mapping.js';
|
||||
import {getProjectReflection} from './project-reflection.js';
|
||||
import {ElasticsearchTemplateCollection} from './types/mapping.js';
|
||||
import {generateTemplate} from './mapping';
|
||||
import {getProjectReflection} from './project-reflection';
|
||||
import {ElasticsearchTemplateCollection} from './types/mapping';
|
||||
|
||||
// handle unhandled promise rejections
|
||||
process.on('unhandledRejection', async (reason: unknown) => {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {MappingFloatNumberProperty} from '@elastic/elasticsearch/lib/api/types';
|
||||
import {ElasticsearchTypemap} from '../types/mapping.js';
|
||||
import {ElasticsearchTypemap} from '../types/mapping';
|
||||
|
||||
export const PARSE_ERROR = 'PARSE_ERROR' as MappingFloatNumberProperty['type'];
|
||||
export const MISSING_PREMAP = 'MISSING_PREMAP' as MappingFloatNumberProperty['type'];
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
export * from './mapping'
|
||||
export * from './project-reflection'
|
||||
export * from './config/premap'
|
||||
export * from './config/fieldmap'
|
||||
export * from './config/settings'
|
||||
export * from './config/typemap'
|
||||
export * from './mapping';
|
||||
export * from './project-reflection';
|
||||
|
||||
export * from './config/premap';
|
||||
export * from './config/fieldmap';
|
||||
export * from './config/settings';
|
||||
export * from './config/typemap';
|
||||
|
||||
export * from './types/mapping';
|
||||
export * from './types/aggregation';
|
||||
|
||||
@@ -33,13 +33,13 @@ import {
|
||||
TypeParameterType,
|
||||
UnionType,
|
||||
} from 'typedoc/dist/lib/models';
|
||||
import {fieldmap, filterableMap, filterableTagName} from './config/fieldmap.js';
|
||||
import {premaps} from './config/premap.js';
|
||||
import {settings} from './config/settings.js';
|
||||
import {dynamicTypes, isTagType, MISSING_PREMAP, PARSE_ERROR, TYPE_CONFLICT, typemap} from './config/typemap.js';
|
||||
import {AggregationSchema, ESNestedAggregation} from './types/aggregation.js';
|
||||
import {fieldmap, filterableMap, filterableTagName} from './config/fieldmap';
|
||||
import {premaps} from './config/premap';
|
||||
import {settings} from './config/settings';
|
||||
import {dynamicTypes, isTagType, MISSING_PREMAP, PARSE_ERROR, TYPE_CONFLICT, typemap} from './config/typemap';
|
||||
import {AggregationSchema, ESNestedAggregation} from './types/aggregation';
|
||||
import {ElasticsearchTemplateCollection,
|
||||
MappingGenTemplate} from './types/mapping.js';
|
||||
MappingGenTemplate} from './types/mapping';
|
||||
import * as console from 'console';
|
||||
|
||||
let dynamicTemplates: Record<string, MappingDynamicTemplate>[] = [];
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Logger} from '@openstapps/logger';
|
||||
import {readdirSync, statSync} from 'fs';
|
||||
import path from 'path';
|
||||
import {MapAggTest} from './mapping-model/map-agg-test.js';
|
||||
@@ -48,8 +47,8 @@ describe('ES Aggregation Gen', async () => {
|
||||
it(test.testName, function () {
|
||||
magAppInstance.testInterfaceAgainstPath(test);
|
||||
});
|
||||
} catch (error: any) {
|
||||
await Logger.error('UNHANDLED REJECTION', error.stack);
|
||||
} catch (error) {
|
||||
console.error('UNHANDLED REJECTION', (error as any).stack);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {ThingType} from './types.js';
|
||||
import {MapAggTestOptions} from '../../map-agg-test-options.js';
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ export const testConfig: MapAggTestOptions = {
|
||||
dynamic: 'strict',
|
||||
properties: {
|
||||
baz: {
|
||||
type: 'float',
|
||||
type: ElasticsearchDataType.float,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Logger} from '@openstapps/logger';
|
||||
import {readdirSync, statSync} from 'fs';
|
||||
import path from 'path';
|
||||
import {MapAggTest} from './mapping-model/map-agg-test.js';
|
||||
@@ -49,8 +48,8 @@ describe('ES Mapping Gen', async () => {
|
||||
it(test.testName, function () {
|
||||
magAppInstance.testInterfaceAgainstPath(test);
|
||||
});
|
||||
} catch (error: any) {
|
||||
await Logger.error('UNHANDLED REJECTION', error.stack);
|
||||
} catch (error) {
|
||||
console.error('UNHANDLED REJECTION', (error as any).stack);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsup --dts",
|
||||
"format": "prettier .",
|
||||
"format:fix": "prettier --write .",
|
||||
"format": "prettier . --ignore-path ../../.gitignore",
|
||||
"format:fix": "prettier --write . --ignore-path ../../.gitignore",
|
||||
"lint": "eslint --ext .ts src/",
|
||||
"lint:fix": "eslint --fix --ext .ts src/"
|
||||
},
|
||||
|
||||
@@ -35,7 +35,7 @@ import {
|
||||
} from './types.js';
|
||||
import got from 'got';
|
||||
|
||||
export * from './types.js'
|
||||
export * from './types.js';
|
||||
|
||||
/**
|
||||
* Sleep for a number of milliseconds
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
## Summary
|
||||
|
||||
(Summarize the bug encountered concisely)
|
||||
|
||||
## Steps to reproduce
|
||||
|
||||
(How one can reproduce the issue - this is very important)
|
||||
|
||||
## Example Project
|
||||
|
||||
(If possible, please create an example project here on GitLab.com that exhibits the problematic behaviour, and link to it here in the bug report)
|
||||
|
||||
(If you are using an older version of GitLab, this will also determine whether the bug has been fixed in a more recent version)
|
||||
|
||||
## What is the current bug behavior?
|
||||
|
||||
(What actually happens)
|
||||
|
||||
## What is the expected correct behavior?
|
||||
|
||||
(What you should see instead)
|
||||
|
||||
## Relevant logs and/or screenshots
|
||||
|
||||
(Paste any relevant logs - please use code blocks (```) to format console output,
|
||||
logs, and code as it's very hard to read otherwise.)
|
||||
|
||||
## Possible fixes
|
||||
|
||||
(If you can, link to the line of code that might be responsible for the problem)
|
||||
|
||||
/label ~meeting
|
||||
@@ -15,25 +15,22 @@
|
||||
"types": "./lib/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "tsup --dts",
|
||||
"format": "prettier .",
|
||||
"format:fix": "prettier --write .",
|
||||
"format": "prettier . --ignore-path ../../.gitignore",
|
||||
"format:fix": "prettier --write . --ignore-path ../../.gitignore",
|
||||
"lint": "eslint --ext .ts src/",
|
||||
"lint:fix": "eslint --fix --ext .ts src/",
|
||||
"test": "nyc mocha 'test/**/*.spec.ts'"
|
||||
"test": "c8 mocha"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/nodemailer": "6.4.7",
|
||||
"chalk": "4.1.2",
|
||||
"chalk": "5.2.0",
|
||||
"flatted": "3.2.7",
|
||||
"moment": "2.29.4",
|
||||
"nodemailer": "6.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@openstapps/eslint-config": "workspace:*",
|
||||
"@openstapps/nyc-config": "workspace:*",
|
||||
"@openstapps/prettier-config": "workspace:*",
|
||||
"@openstapps/tsconfig": "workspace:*",
|
||||
"@testdeck/mocha": "0.3.3",
|
||||
"@types/chai": "4.3.4",
|
||||
"@types/chai-as-promised": "7.1.5",
|
||||
"@types/chai-spies": "1.0.3",
|
||||
@@ -43,7 +40,7 @@
|
||||
"chai-as-promised": "7.1.1",
|
||||
"chai-spies": "1.0.0",
|
||||
"mocha": "10.2.0",
|
||||
"nyc": "15.1.0",
|
||||
"c8": "7.13.0",
|
||||
"ts-node": "10.9.1",
|
||||
"tsup": "6.7.0",
|
||||
"typedoc": "0.23.28",
|
||||
@@ -63,8 +60,5 @@
|
||||
"extends": [
|
||||
"@openstapps"
|
||||
]
|
||||
},
|
||||
"nyc": {
|
||||
"extends": "@openstapps/nyc-config"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
export * from './logger.js'
|
||||
export * from './common.js'
|
||||
export * from './smtp.js'
|
||||
export * from './transformation.js'
|
||||
export * from './transport.js'
|
||||
export * from './logger.js';
|
||||
export * from './common.js';
|
||||
export * from './smtp.js';
|
||||
export * from './transformation.js';
|
||||
export * from './transport.js';
|
||||
|
||||
export * from './transformations/add-log-level.js'
|
||||
export * from './transformations/colorize.js'
|
||||
export * from './transformations/timestamp.js'
|
||||
export * from './transformations/add-log-level.js';
|
||||
export * from './transformations/colorize.js';
|
||||
export * from './transformations/timestamp.js';
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import chalk from 'chalk';
|
||||
// eslint-disable-next-line unicorn/import-style
|
||||
import type {ChalkInstance} from 'chalk';
|
||||
import {LogLevel} from '../logger.js';
|
||||
import {Transformation} from '../transformation.js';
|
||||
|
||||
@@ -31,7 +33,8 @@ export class Colorize implements Transformation {
|
||||
* @param logLevelToColor Map from log level to color transformation to apply
|
||||
*/
|
||||
constructor(
|
||||
private readonly logLevelToColor: {[k in LogLevel]: chalk.Chalk} = {
|
||||
// not entirely sure why we can't just use the functions directly here
|
||||
private readonly logLevelToColor: {[k in LogLevel]: ChalkInstance} = {
|
||||
ERROR: chalk.bold.red,
|
||||
INFO: chalk.cyan,
|
||||
LOG: chalk.white,
|
||||
|
||||
@@ -13,18 +13,15 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {expect} from 'chai';
|
||||
import {suite, test} from '@testdeck/mocha';
|
||||
import {
|
||||
deleteUndefinedProperties,
|
||||
isNodeEnvironment,
|
||||
isProductiveEnvironment,
|
||||
isProductiveNodeEnvironment,
|
||||
} from '../src/common.js';
|
||||
} from '../src/index.js';
|
||||
|
||||
@suite()
|
||||
export class CommonSpec {
|
||||
@test
|
||||
deleteUndefinedProperties1() {
|
||||
describe('common', function () {
|
||||
it('should should delete undefined properties (1)', function () {
|
||||
expect(
|
||||
deleteUndefinedProperties({
|
||||
a: 2,
|
||||
@@ -39,20 +36,18 @@ export class CommonSpec {
|
||||
c: 3,
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
deleteUndefinedProperties2() {
|
||||
it('should delete undefined properties (2)', function () {
|
||||
expect(
|
||||
deleteUndefinedProperties({
|
||||
a: undefined,
|
||||
b: undefined,
|
||||
}),
|
||||
).to.deep.equal({});
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
deleteUndefinedProperties3() {
|
||||
it('should delete undefined properties (3)', function () {
|
||||
expect(
|
||||
deleteUndefinedProperties({
|
||||
a: 2,
|
||||
@@ -64,49 +59,41 @@ export class CommonSpec {
|
||||
b: 'foo',
|
||||
c: 'bar',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
isNodeEnvironment() {
|
||||
it('should detect node environment', function () {
|
||||
expect(isNodeEnvironment()).to.be.equal(true);
|
||||
|
||||
const savedProcess = process;
|
||||
|
||||
// @ts-ignore
|
||||
// @ts-expect-error override this
|
||||
process = undefined;
|
||||
|
||||
expect(isNodeEnvironment()).to.be.equal(false);
|
||||
|
||||
process = savedProcess;
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
isProductiveEnvironment() {
|
||||
const nodeEnv = process.env.NODE_ENV;
|
||||
it('should detect production environment', function () {
|
||||
const nodeEnvironment = process.env.NODE_ENV;
|
||||
|
||||
process.env.NODE_ENV = '';
|
||||
|
||||
expect(isProductiveEnvironment()).to.be.equal(false);
|
||||
|
||||
process.env.NODE_ENV = 'production';
|
||||
|
||||
expect(isProductiveEnvironment()).to.be.equal(true);
|
||||
|
||||
process.env.NODE_ENV = nodeEnv;
|
||||
}
|
||||
process.env.NODE_ENV = nodeEnvironment;
|
||||
});
|
||||
|
||||
@test
|
||||
isProductiveNodeEnvironment() {
|
||||
const nodeEnv = process.env.NODE_ENV;
|
||||
it('should detect node production environment', function () {
|
||||
const nodeEnvironment = process.env.NODE_ENV;
|
||||
|
||||
process.env.NODE_ENV = '';
|
||||
|
||||
expect(isProductiveNodeEnvironment()).to.be.equal(false);
|
||||
|
||||
process.env.NODE_ENV = 'production';
|
||||
|
||||
expect(isProductiveNodeEnvironment()).to.be.equal(true);
|
||||
|
||||
process.env.NODE_ENV = nodeEnv;
|
||||
}
|
||||
}
|
||||
process.env.NODE_ENV = nodeEnvironment;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Transport, VerifiableTransport} from '../src/transport.js';
|
||||
import {Transport, VerifiableTransport} from '../src/index.js';
|
||||
|
||||
export class DummyTransport extends Transport {
|
||||
send(subject: string, message: string): Promise<string> {
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/*
|
||||
* Copyright (C) 2018, 2020 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
@@ -16,41 +17,35 @@ import chai from 'chai';
|
||||
import {expect} from 'chai';
|
||||
import chaiAsPromised from 'chai-as-promised';
|
||||
import chaiSpies from 'chai-spies';
|
||||
import {suite, test} from '@testdeck/mocha';
|
||||
import {Logger} from '../src/logger.js';
|
||||
import {AddLogLevel} from '../src/transformations/add-log-level.js';
|
||||
import {Colorize} from '../src/transformations/colorize.js';
|
||||
import {DummyTransport} from './dummyTransport.js';
|
||||
import {Logger, AddLogLevel, Colorize} from '../src/index.js';
|
||||
import {DummyTransport} from './dummy-transport.js';
|
||||
import path from 'node:path';
|
||||
import chalk from 'chalk';
|
||||
|
||||
chai.should();
|
||||
chai.use(chaiSpies);
|
||||
chai.use(chaiAsPromised);
|
||||
|
||||
@suite()
|
||||
export class LoggerSpec {
|
||||
static 'sandbox': ChaiSpies.Sandbox;
|
||||
chalk.level = 2;
|
||||
|
||||
static 'before'() {
|
||||
LoggerSpec.sandbox = chai.spy.sandbox();
|
||||
}
|
||||
describe('Logger', function () {
|
||||
const sandbox = chai.spy.sandbox();
|
||||
|
||||
'before'() {
|
||||
beforeEach(function () {
|
||||
Logger.setTransformations([new AddLogLevel()]);
|
||||
}
|
||||
});
|
||||
|
||||
'after'() {
|
||||
LoggerSpec.sandbox.restore();
|
||||
}
|
||||
afterEach(function () {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
@test
|
||||
async 'default log level'() {
|
||||
it('should read default log level', async function () {
|
||||
expect((Logger as any).getLevel('LOG')).to.be.equal(31);
|
||||
expect((Logger as any).getLevel('EXIT')).to.be.equal(0);
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async 'error'() {
|
||||
const spy = LoggerSpec.sandbox.on(console, 'error', () => {
|
||||
it('should error', async function () {
|
||||
const spy = sandbox.on(console, 'error', () => {
|
||||
// noop
|
||||
});
|
||||
|
||||
@@ -59,15 +54,14 @@ export class LoggerSpec {
|
||||
expect(spy).to.have.been.called();
|
||||
expect(spy.__spy.calls[0][0]).to.contain('[ERROR]');
|
||||
expect(spy.__spy.calls[0][0]).to.contain('Foobar');
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async 'error in productive environment'() {
|
||||
const spy = LoggerSpec.sandbox.on(console, 'error', () => {
|
||||
it('should error in productive environment', async function () {
|
||||
const spy = sandbox.on(console, 'error', () => {
|
||||
// noop
|
||||
});
|
||||
|
||||
const nodeEnv = process.env.NODE_ENV;
|
||||
const nodeEnvironment = process.env.NODE_ENV;
|
||||
process.env.NODE_ENV = 'production';
|
||||
|
||||
await Logger.error('Foobar').should.be.rejectedWith(Error);
|
||||
@@ -87,12 +81,11 @@ export class LoggerSpec {
|
||||
|
||||
Logger.setTransport();
|
||||
|
||||
process.env.NODE_ENV = nodeEnv;
|
||||
}
|
||||
process.env.NODE_ENV = nodeEnvironment;
|
||||
});
|
||||
|
||||
@test
|
||||
async 'error without output'() {
|
||||
const spy = LoggerSpec.sandbox.on(console, 'error', () => {
|
||||
it('should error without output', async function () {
|
||||
const spy = sandbox.on(console, 'error', () => {
|
||||
// noop
|
||||
});
|
||||
|
||||
@@ -103,24 +96,24 @@ export class LoggerSpec {
|
||||
delete process.env.STAPPS_LOG_LEVEL;
|
||||
|
||||
expect(spy).not.to.have.been.called();
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async 'error with Error'() {
|
||||
const spy = LoggerSpec.sandbox.on(console, 'error', () => {
|
||||
it('should error with Error', async function () {
|
||||
const spy = sandbox.on(console, 'error', () => {
|
||||
// noop
|
||||
});
|
||||
|
||||
// eslint-disable-next-line unicorn/error-message
|
||||
await Logger.error(new Error());
|
||||
|
||||
expect(spy).to.have.been.called();
|
||||
expect(spy.__spy.calls[0][0]).to.contain('Error');
|
||||
expect(spy.__spy.calls[0][0]).to.contain(process.cwd());
|
||||
}
|
||||
const directory = process.cwd().replaceAll(path.sep, path.posix.sep);
|
||||
expect(spy.__spy.calls[0][0]).to.contain(directory);
|
||||
});
|
||||
|
||||
@test
|
||||
'info'() {
|
||||
const spy = LoggerSpec.sandbox.on(console, 'info', () => {
|
||||
it('should info', function () {
|
||||
const spy = sandbox.on(console, 'info', () => {
|
||||
// noop
|
||||
});
|
||||
|
||||
@@ -129,23 +122,22 @@ export class LoggerSpec {
|
||||
expect(spy).to.have.been.called();
|
||||
expect(spy.__spy.calls[0][0]).to.contain('[INFO]');
|
||||
expect(spy.__spy.calls[0][0]).to.contain('Foobar');
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
async 'exits'() {
|
||||
const infoSpy = LoggerSpec.sandbox.on(console, 'info', () => {
|
||||
it('should exit', async function () {
|
||||
const infoSpy = sandbox.on(console, 'info', () => {
|
||||
// noop
|
||||
});
|
||||
const logSpy = LoggerSpec.sandbox.on(console, 'log', () => {
|
||||
const logSpy = sandbox.on(console, 'log', () => {
|
||||
// noop
|
||||
});
|
||||
const warnSpy = LoggerSpec.sandbox.on(console, 'warn', () => {
|
||||
const warnSpy = sandbox.on(console, 'warn', () => {
|
||||
// noop
|
||||
});
|
||||
const errorSpy = LoggerSpec.sandbox.on(console, 'error', () => {
|
||||
const errorSpy = sandbox.on(console, 'error', () => {
|
||||
// noop
|
||||
});
|
||||
const processSpy = LoggerSpec.sandbox.on(process, 'exit', () => {
|
||||
const processSpy = sandbox.on(process, 'exit', () => {
|
||||
// noop
|
||||
});
|
||||
|
||||
@@ -173,11 +165,10 @@ export class LoggerSpec {
|
||||
expect(processSpy).to.have.been.called.exactly(5);
|
||||
|
||||
process.env.STAPPS_EXIT_LEVEL = exitLevel;
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
'info without output'() {
|
||||
const spy = LoggerSpec.sandbox.on(console, 'info', () => {
|
||||
it('should info without output', function () {
|
||||
const spy = sandbox.on(console, 'info', () => {
|
||||
// noop
|
||||
});
|
||||
|
||||
@@ -188,10 +179,9 @@ export class LoggerSpec {
|
||||
delete process.env.STAPPS_LOG_LEVEL;
|
||||
|
||||
expect(spy).not.to.have.been.called;
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
'initialized'() {
|
||||
it('should be initialized', function () {
|
||||
Logger.setTransport(new DummyTransport());
|
||||
|
||||
expect(() => {
|
||||
@@ -199,11 +189,10 @@ export class LoggerSpec {
|
||||
}).not.to.throw();
|
||||
|
||||
Logger.setTransport();
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
'initialized in productive environment'() {
|
||||
const nodeEnv = process.env.NODE_ENV;
|
||||
it('should be initialized in productive environment', function () {
|
||||
const nodeEnvironment = process.env.NODE_ENV;
|
||||
process.env.NODE_ENV = 'production';
|
||||
|
||||
Logger.setTransport(new DummyTransport());
|
||||
@@ -218,7 +207,7 @@ export class LoggerSpec {
|
||||
Logger.initialized();
|
||||
}).to.throw();
|
||||
|
||||
const spy = LoggerSpec.sandbox.on(console, 'warn', () => {
|
||||
const spy = sandbox.on(console, 'warn', () => {
|
||||
// noop
|
||||
});
|
||||
|
||||
@@ -232,14 +221,13 @@ export class LoggerSpec {
|
||||
|
||||
expect(spy).to.have.been.called();
|
||||
|
||||
process.env.NODE_ENV = nodeEnv;
|
||||
}
|
||||
process.env.NODE_ENV = nodeEnvironment;
|
||||
});
|
||||
|
||||
@test
|
||||
'is compatible with log aggregation in productive environment'() {
|
||||
it('should be compatible with log aggregation in productive environment', function () {
|
||||
Logger.setTransformations([new AddLogLevel(), new Colorize()]);
|
||||
|
||||
let spy = LoggerSpec.sandbox.on(console, 'log', () => {
|
||||
const spy = sandbox.on(console, 'log', () => {
|
||||
// noop
|
||||
});
|
||||
|
||||
@@ -248,7 +236,7 @@ export class LoggerSpec {
|
||||
expect(spy).to.have.been.called.once;
|
||||
expect(spy.__spy.calls[0][0]).to.equal('\u001B[37m[LOG] Foo\u001B[39m\n\u001B[37mbar\u001B[39m');
|
||||
|
||||
const nodeEnv = process.env.NODE_ENV;
|
||||
const nodeEnvironment = process.env.NODE_ENV;
|
||||
process.env.NODE_ENV = 'production';
|
||||
process.env.ALLOW_NO_TRANSPORT = 'true';
|
||||
|
||||
@@ -259,13 +247,12 @@ export class LoggerSpec {
|
||||
expect(spy).to.have.been.called.twice;
|
||||
expect(spy.__spy.calls[1][0]).to.equal('[LOG] Foo bar');
|
||||
|
||||
process.env.NODE_ENV = nodeEnv;
|
||||
process.env.NODE_ENV = nodeEnvironment;
|
||||
delete process.env.ALLOW_NO_TRANSPORT;
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
'log'() {
|
||||
const spy = LoggerSpec.sandbox.on(console, 'log', () => {
|
||||
it('should log', function () {
|
||||
const spy = sandbox.on(console, 'log', () => {
|
||||
// noop
|
||||
});
|
||||
|
||||
@@ -274,11 +261,10 @@ export class LoggerSpec {
|
||||
expect(spy).to.have.been.called();
|
||||
expect(spy.__spy.calls[0][0]).to.contain('[LOG]');
|
||||
expect(spy.__spy.calls[0][0]).to.contain('Foobar');
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
'log without output'() {
|
||||
const spy = LoggerSpec.sandbox.on(console, 'log', () => {
|
||||
it('should log without output', function () {
|
||||
const spy = sandbox.on(console, 'log', () => {
|
||||
// noop
|
||||
});
|
||||
|
||||
@@ -289,11 +275,10 @@ export class LoggerSpec {
|
||||
delete process.env.STAPPS_LOG_LEVEL;
|
||||
|
||||
expect(spy).to.not.have.been.called();
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
'ok'() {
|
||||
const spy = LoggerSpec.sandbox.on(console, 'log', () => {
|
||||
it('should ok', function () {
|
||||
const spy = sandbox.on(console, 'log', () => {
|
||||
// noop
|
||||
});
|
||||
|
||||
@@ -302,11 +287,10 @@ export class LoggerSpec {
|
||||
expect(spy).to.have.been.called();
|
||||
expect(spy.__spy.calls[0][0]).to.contain('[OK]');
|
||||
expect(spy.__spy.calls[0][0]).to.contain('Foobar');
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
'ok without output'() {
|
||||
const spy = LoggerSpec.sandbox.on(console, 'log', () => {
|
||||
it('should ok without output', function () {
|
||||
const spy = sandbox.on(console, 'log', () => {
|
||||
// noop
|
||||
});
|
||||
|
||||
@@ -317,19 +301,17 @@ export class LoggerSpec {
|
||||
delete process.env.STAPPS_LOG_LEVEL;
|
||||
|
||||
expect(spy).not.to.have.been.called();
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
'setTransport'() {
|
||||
it('should set transport', function () {
|
||||
expect(() => {
|
||||
Logger.setTransport(new DummyTransport());
|
||||
Logger.setTransport();
|
||||
}).not.to.throw();
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
'stringify'() {
|
||||
const spy = LoggerSpec.sandbox.on(console, 'log', () => {
|
||||
it('should stringify', function () {
|
||||
const spy = sandbox.on(console, 'log', () => {
|
||||
// noop
|
||||
});
|
||||
|
||||
@@ -338,11 +320,10 @@ export class LoggerSpec {
|
||||
expect(spy).to.have.been.called();
|
||||
expect(spy.__spy.calls[0][0]).to.contain('foo');
|
||||
expect(spy.__spy.calls[0][0]).to.contain('bar');
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
'stringify object'() {
|
||||
const spy = LoggerSpec.sandbox.on(console, 'log', () => {
|
||||
it('should stringify object', function () {
|
||||
const spy = sandbox.on(console, 'log', () => {
|
||||
// noop
|
||||
});
|
||||
|
||||
@@ -353,11 +334,10 @@ export class LoggerSpec {
|
||||
expect(spy).to.have.been.called();
|
||||
expect(spy.__spy.calls[0][0]).to.contain('foo');
|
||||
expect(spy.__spy.calls[0][0]).to.contain('bar');
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
'warn'() {
|
||||
const spy = LoggerSpec.sandbox.on(console, 'warn', () => {
|
||||
it('should warn', function () {
|
||||
const spy = sandbox.on(console, 'warn', () => {
|
||||
// noop
|
||||
});
|
||||
|
||||
@@ -366,11 +346,10 @@ export class LoggerSpec {
|
||||
expect(spy).to.have.been.called();
|
||||
expect(spy.__spy.calls[0][0]).to.contain('[WARN]');
|
||||
expect(spy.__spy.calls[0][0]).to.contain('Foobar');
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
'warn without output'() {
|
||||
const spy = LoggerSpec.sandbox.on(console, 'warn', () => {
|
||||
it('should warn without output', function () {
|
||||
const spy = sandbox.on(console, 'warn', () => {
|
||||
// noop
|
||||
});
|
||||
|
||||
@@ -381,17 +360,16 @@ export class LoggerSpec {
|
||||
delete process.env.STAPPS_LOG_LEVEL;
|
||||
|
||||
expect(spy).not.to.have.been.called();
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
'log level exclusiveness'() {
|
||||
const warnSpy = LoggerSpec.sandbox.on(console, 'warn', () => {
|
||||
it('should log level exclusiveness', function () {
|
||||
const warnSpy = sandbox.on(console, 'warn', () => {
|
||||
// noop WARN
|
||||
});
|
||||
const infoSpy = LoggerSpec.sandbox.on(console, 'info', () => {
|
||||
const infoSpy = sandbox.on(console, 'info', () => {
|
||||
// noop INFO
|
||||
});
|
||||
const okSpy = LoggerSpec.sandbox.on(console, 'log', () => {
|
||||
const okSpy = sandbox.on(console, 'log', () => {
|
||||
// noop OK
|
||||
});
|
||||
|
||||
@@ -413,20 +391,19 @@ export class LoggerSpec {
|
||||
expect(okSpy).to.not.have.been.called();
|
||||
|
||||
delete process.env.STAPPS_LOG_LEVEL;
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
'getExitLevel'() {
|
||||
it('should getExitLevel', function () {
|
||||
const savedProcess = process;
|
||||
|
||||
// @ts-ignore
|
||||
// @ts-expect-error ignore
|
||||
process = undefined;
|
||||
|
||||
(global as any).window = {
|
||||
STAPPS_EXIT_LEVEL: 0,
|
||||
};
|
||||
|
||||
const stub = LoggerSpec.sandbox.on(console, 'info', () => {
|
||||
const stub = sandbox.on(console, 'info', () => {
|
||||
// noop
|
||||
});
|
||||
|
||||
@@ -437,20 +414,19 @@ export class LoggerSpec {
|
||||
delete (global as any).window;
|
||||
|
||||
expect(stub).not.to.have.been.called();
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
'getLogLevel'() {
|
||||
it('should getLogLevel', function () {
|
||||
const savedProcess = process;
|
||||
|
||||
// @ts-ignore
|
||||
// @ts-expect-error ignore
|
||||
process = undefined;
|
||||
|
||||
(global as any).window = {
|
||||
STAPPS_LOG_LEVEL: 0,
|
||||
};
|
||||
|
||||
const stub = LoggerSpec.sandbox.on(console, 'info', () => {
|
||||
const stub = sandbox.on(console, 'info', () => {
|
||||
// noop
|
||||
});
|
||||
|
||||
@@ -461,20 +437,19 @@ export class LoggerSpec {
|
||||
delete (global as any).window;
|
||||
|
||||
expect(stub).not.to.have.been.called();
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
'output without transformations'() {
|
||||
it('should output without transformations', function () {
|
||||
Logger.setTransformations([]);
|
||||
|
||||
const stub = LoggerSpec.sandbox.on(console, 'log', () => {
|
||||
const stub = sandbox.on(console, 'log', () => {
|
||||
// noop
|
||||
});
|
||||
const applyTransformationsSpy = LoggerSpec.sandbox.on(new Logger(), 'applyTransformations');
|
||||
const applyTransformationsSpy = sandbox.on(new Logger(), 'applyTransformations');
|
||||
|
||||
Logger.log('Foobar');
|
||||
|
||||
expect(stub).to.have.been.called.with('Foobar');
|
||||
expect(applyTransformationsSpy).not.to.have.been.called;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,96 +13,42 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {expect} from 'chai';
|
||||
import {suite, test} from '@testdeck/mocha';
|
||||
import {SMTP} from '../src/smtp.js';
|
||||
import {SMTP} from '../src/index.js';
|
||||
|
||||
@suite()
|
||||
export class SMTPSpec {
|
||||
/* tslint:disable:member-ordering */
|
||||
@test
|
||||
mailValidation1() {
|
||||
expect(SMTP.isValidEmailAddress('stordeur@campus.tu-berlin.de')).to.be.true;
|
||||
}
|
||||
const validEmails = [
|
||||
'stordeur@campus.tu-berlin.de',
|
||||
'foo@bar.com',
|
||||
'test@test.cz',
|
||||
'info@beispiel.to',
|
||||
'stördeur@campus.tu-berlin.de',
|
||||
'stordeur@campus.tu-berlin.de+a',
|
||||
];
|
||||
|
||||
@test
|
||||
mailValidation2() {
|
||||
expect(SMTP.isValidEmailAddress('foo@bar.com')).to.be.true;
|
||||
}
|
||||
const invalidEmails = [
|
||||
'stordeurcampus.tu-berlin.de',
|
||||
'@campus.tu-berlin.de',
|
||||
'',
|
||||
'@',
|
||||
' stordeur@campus.tu-berlin.de',
|
||||
'stord+eur@campus.tu-berlin.de ',
|
||||
'stordeur@campus..tu-berlin.de',
|
||||
'stordeur@campus',
|
||||
];
|
||||
|
||||
@test
|
||||
mailValidation3() {
|
||||
expect(SMTP.isValidEmailAddress('test@test.cz')).to.be.true;
|
||||
}
|
||||
describe('isValidEmailAddress', function () {
|
||||
describe('valid emails', function () {
|
||||
for (const email of validEmails) {
|
||||
it(`should detect "${email}" as valid`, function () {
|
||||
expect(SMTP.isValidEmailAddress(email)).to.be.true;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@test
|
||||
mailValidation4() {
|
||||
expect(SMTP.isValidEmailAddress('info@beispiel.to')).to.be.true;
|
||||
}
|
||||
|
||||
@test
|
||||
mailValidation5() {
|
||||
expect(SMTP.isValidEmailAddress('stördeur@campus.tu-berlin.de')).to.be.true;
|
||||
}
|
||||
|
||||
@test
|
||||
mailValidation6() {
|
||||
expect(SMTP.isValidEmailAddress('stordeur@campus.tu-berlin.de+a')).to.be.true;
|
||||
}
|
||||
|
||||
@test
|
||||
mailValidation7() {
|
||||
expect(SMTP.isValidEmailAddress('stordeurcampus.tu-berlin.de')).to.be.false;
|
||||
}
|
||||
|
||||
@test
|
||||
mailValidation8() {
|
||||
expect(SMTP.isValidEmailAddress('@campus.tu-berlin.de')).to.be.false;
|
||||
}
|
||||
|
||||
@test
|
||||
mailValidation9() {
|
||||
expect(SMTP.isValidEmailAddress('')).to.be.false;
|
||||
}
|
||||
|
||||
@test
|
||||
mailValidation10() {
|
||||
expect(SMTP.isValidEmailAddress('@')).to.be.false;
|
||||
}
|
||||
|
||||
@test
|
||||
mailValidation11() {
|
||||
expect(SMTP.isValidEmailAddress('@')).to.be.false;
|
||||
}
|
||||
|
||||
@test
|
||||
mailValidation12() {
|
||||
expect(SMTP.isValidEmailAddress(' stordeur@campus.tu-berlin.de')).to.be.false;
|
||||
}
|
||||
|
||||
@test
|
||||
mailValidation13() {
|
||||
expect(SMTP.isValidEmailAddress('stordeur@campus.tu-berlin.de ')).to.be.false;
|
||||
}
|
||||
|
||||
@test
|
||||
mailValidation14() {
|
||||
expect(SMTP.isValidEmailAddress('stord+eur@campus.tu-berlin.de ')).to.be.false;
|
||||
}
|
||||
|
||||
@test
|
||||
mailValidation15() {
|
||||
expect(SMTP.isValidEmailAddress('anselm..stordeur@campus.tu-berlin.de')).to.be.false;
|
||||
}
|
||||
|
||||
@test
|
||||
mailValidation16() {
|
||||
expect(SMTP.isValidEmailAddress('stordeur@campus..tu-berlin.de')).to.be.false;
|
||||
}
|
||||
|
||||
@test
|
||||
mailValidation17() {
|
||||
expect(SMTP.isValidEmailAddress('stordeur@campus')).to.be.false;
|
||||
}
|
||||
|
||||
/* tslint:enable:member-ordering */
|
||||
}
|
||||
describe('invalid emails', function () {
|
||||
for (const email of invalidEmails) {
|
||||
it(`should detect "${email}" as invalid`, function () {
|
||||
expect(SMTP.isValidEmailAddress(email)).to.be.false;
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,15 +13,12 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {expect} from 'chai';
|
||||
import {suite, test} from '@testdeck/mocha';
|
||||
import {AddLogLevel} from '../../src/transformations/add-log-level.js';
|
||||
import {AddLogLevel} from '../../src/index.js';
|
||||
|
||||
@suite()
|
||||
export class AddLogLevelSpec {
|
||||
@test
|
||||
transform() {
|
||||
describe('add log level', function () {
|
||||
it('should transform', function () {
|
||||
const transformation = new AddLogLevel();
|
||||
|
||||
expect(transformation.transform('ERROR', 'Foobar')).to.be.equal('[ERROR] Foobar');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,18 +13,18 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {expect} from 'chai';
|
||||
import {suite, test} from '@testdeck/mocha';
|
||||
import {Colorize} from '../../src/transformations/colorize.js';
|
||||
import {Colorize} from '../../src/index.js';
|
||||
import chalk from 'chalk';
|
||||
|
||||
@suite()
|
||||
export class ColorizeSpec {
|
||||
@test
|
||||
transform() {
|
||||
chalk.level = 2;
|
||||
|
||||
describe('colorize', function () {
|
||||
it('should transform', function () {
|
||||
const transformation = new Colorize();
|
||||
|
||||
expect(transformation.transform('ERROR', 'Foobar')).to.be.equal(
|
||||
'\u001b[1m\u001b[31mFoobar\u001b[39m\u001b[22m',
|
||||
'\u001B[1m\u001B[31mFoobar\u001B[39m\u001B[22m',
|
||||
);
|
||||
expect(transformation.transform('LOG', 'Foobar')).to.be.equal('\u001b[37mFoobar\u001b[39m');
|
||||
}
|
||||
}
|
||||
expect(transformation.transform('LOG', 'Foobar')).to.be.equal('\u001B[37mFoobar\u001B[39m');
|
||||
});
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user