Skip to content

Commit bdfc00b

Browse files
committed
test: Add integration tests with vitest
1 parent cec87fa commit bdfc00b

File tree

14 files changed

+1554
-1896
lines changed

14 files changed

+1554
-1896
lines changed

demo/seed.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[
2+
{
3+
"email": "[email protected]",
4+
"password": "abc123",
5+
"pods": [{
6+
"name": "ruben"
7+
}]
8+
},
9+
{
10+
"email": "[email protected]",
11+
"password": "abc123",
12+
"pods": [
13+
{
14+
"name": "demo"
15+
}
16+
]
17+
}
18+
]

package.json

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
}
4343
],
4444
"private": true,
45-
"packageManager": "yarn@4.1.0",
45+
"packageManager": "yarn@4.9.2",
4646
"engines": {
4747
"node": ">=20.0",
4848
"yarn": ">=4.0"
@@ -54,7 +54,7 @@
5454
"postinstall": "yarn run sync:list && yarn build",
5555
"clean": "shx rm -rf ./**/node_modules",
5656
"build": "yarn workspaces foreach --include 'packages/*' -A -pi -j unlimited -t run build",
57-
"test": "yarn workspaces foreach --include 'packages/*' -A -pi -j unlimited run test",
57+
"test": "vitest run",
5858
"start": "yarn workspaces foreach --include 'packages/*' -A -pi -j unlimited run start",
5959
"start:odrl": "yarn workspace @solidlab/uma run start:odrl & yarn workspace @solidlab/uma-css run start",
6060
"start:demo": "yarn workspaces foreach --include 'packages/*' -A -pi -j unlimited run demo",
@@ -73,31 +73,26 @@
7373
"@commitlint/cli": "^16.1.0",
7474
"@commitlint/config-conventional": "^16.0.0",
7575
"@types/jest": "^29.5.12",
76-
"@types/node": "^20.11.25",
76+
"@types/node": "^20.19.1",
7777
"@typescript-eslint/eslint-plugin": "^5.12.1",
7878
"@typescript-eslint/parser": "^5.12.1",
7979
"chalk": "^5.4.1",
8080
"componentsjs-generator": "^3.1.2",
8181
"eslint": "^8.10.0",
82-
"jest": "^29.7.0",
8382
"jest-rdf": "^1.8.1",
8483
"shx": "^0.3.4",
8584
"syncpack": "^13.0.2",
86-
"ts-jest": "^29.1.2",
8785
"tsx": "^4.19.2",
88-
"typescript": "^5.3.3"
86+
"typescript": "^5.8.3",
87+
"vite": "^6.3.5",
88+
"vitest": "^3.2.3"
8989
},
9090
"resolutions": {
91-
"@types/node": "^20.11.25"
91+
"@types/node": "^20.19.1"
9292
},
9393
"workspaces": [
9494
"packages/*"
9595
],
96-
"jest": {
97-
"projects": [
98-
"./packages/*/package.json"
99-
]
100-
},
10196
"eslintConfig": {
10297
"env": {
10398
"browser": true,

packages/css/package.json

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
}
3737
],
3838
"private": true,
39-
"packageManager": "yarn@4.0.2",
39+
"packageManager": "yarn@4.9.2",
4040
"engines": {
4141
"node": ">=20.0",
4242
"yarn": ">=4.0"
@@ -59,7 +59,6 @@
5959
"build": "yarn build:ts && yarn build:components",
6060
"build:ts": "yarn run -T tsc",
6161
"build:components": "yarn run -T componentsjs-generator -r uma-css -s src/ -c dist/components -i .componentsignore --lenient",
62-
"test": "yarn run -T jest --coverage",
6362
"start:unseeded": "yarn run community-solid-server -m . -c ./config/default.json -a http://localhost:4000/",
6463
"start": "yarn run community-solid-server -m . -c ./config/default.json --seedConfig ./config/seed.json -a http://localhost:4000/",
6564
"demo": "yarn run demo:setup && yarn run demo:start",
@@ -76,11 +75,6 @@
7675
"jose": "^5.2.2",
7776
"n3": "^1.17.2"
7877
},
79-
"jest": {
80-
"preset": "ts-jest",
81-
"testEnvironment": "node",
82-
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts)$"
83-
},
8478
"lsd:module": "https://linkedsoftwaredependencies.org/bundles/npm/@solidlab/uma-css",
8579
"lsd:components": "dist/components/components.jsonld",
8680
"lsd:contexts": {

packages/ucp/jest.config.js

Lines changed: 0 additions & 20 deletions
This file was deleted.

packages/ucp/jest.coverage.config.js

Lines changed: 0 additions & 13 deletions
This file was deleted.

packages/ucp/package.json

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
}
3232
],
3333
"private": true,
34-
"packageManager": "yarn@4.0.2",
34+
"packageManager": "yarn@4.9.2",
3535
"engines": {
3636
"node": ">=20.0",
3737
"yarn": ">=4.0"
@@ -53,14 +53,7 @@
5353
"scripts": {
5454
"build": "yarn build:ts && yarn build:components",
5555
"build:ts": "yarn run -T tsc",
56-
"build:components": "yarn run -T componentsjs-generator -r ucp -s src -c dist/components -i .componentsignore --lenient",
57-
"test": "yarn run test:unit && yarn run test:integration",
58-
"test:unit": "jest test/unit",
59-
"test:integration": "yarn run test:engines && yarn exec ts-node test/integration/ContainerRulesStorage.ts",
60-
"test:engines": "yarn run test:log-engine && yarn run test:crud-engine && yarn run test:crud-temporal-engine",
61-
"test:log-engine": "yarn exec ts-node test/integration/LogEngine.ts",
62-
"test:crud-engine": "yarn exec ts-node test/integration/CrudEngine.ts",
63-
"test:crud-temporal-engine": "yarn exec ts-node test/integration/CrudEngineTemporal.ts"
56+
"build:components": "yarn run -T componentsjs-generator -r ucp -s src -c dist/components -i .componentsignore --lenient"
6457
},
6558
"dependencies": {
6659
"@smessie/readable-web-to-node-stream": "^3.0.3",

packages/uma/package.json

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
}
3333
],
3434
"private": true,
35-
"packageManager": "yarn@4.0.2",
35+
"packageManager": "yarn@4.9.2",
3636
"engines": {
3737
"node": ">=20.0",
3838
"yarn": ">=4.0"
@@ -55,7 +55,6 @@
5555
"build": "yarn build:ts && yarn build:components",
5656
"build:ts": "yarn run -T tsc",
5757
"build:components": "yarn run -T componentsjs-generator -r sai-uma -s src -c dist/components -i .componentsignore --lenient",
58-
"test": "yarn run -T jest --coverage",
5958
"start": "yarn run -T tsx bin/main.ts",
6059
"start:odrl": "yarn run -T tsx bin/odrl.ts",
6160
"demo": "yarn run -T tsx bin/demo.ts"
@@ -76,11 +75,6 @@
7675
"uri-template-lite": "^23.4.0",
7776
"winston": "^3.11.0"
7877
},
79-
"jest": {
80-
"preset": "ts-jest",
81-
"testEnvironment": "node",
82-
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts)$"
83-
},
8478
"lsd:module": "https://linkedsoftwaredependencies.org/bundles/npm/@solidlab/uma",
8579
"lsd:components": "dist/components/components.jsonld",
8680
"lsd:contexts": {

packages/uma/src/policies/contracts/ContractManager.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ export class ContractManager {
2525
}
2626

2727
createContract(perms: Permission[]): ODRLContract {
28-
console.log('Creating Contract', JSON.stringify(perms, null, 2))
29-
3028
// todo: un-mock this!!!
3129
type Pair = { action: string, target: string };
3230
const permissionPairs: Pair[] = perms.flatMap(

test/integration/Base.test.ts

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
import { App, setGlobalLoggerFactory, WinstonLoggerFactory } from '@solid/community-server';
2+
import * as path from 'node:path';
3+
import { getDefaultCssVariables, instantiateFromConfig } from '../util/ServerUtil';
4+
5+
const cssPort = 3001;
6+
const umaPort = 4001;
7+
8+
describe('A server setup', (): void => {
9+
let umaApp: App;
10+
let cssApp: App;
11+
12+
beforeAll(async(): Promise<void> => {
13+
setGlobalLoggerFactory(new WinstonLoggerFactory('off'));
14+
15+
umaApp = await instantiateFromConfig(
16+
'urn:uma:default:App',
17+
path.join(__dirname, '../../packages/uma/config/default.json'),
18+
{
19+
'urn:uma:variables:port': umaPort,
20+
'urn:uma:variables:baseUrl': `http://localhost:${umaPort}/uma`,
21+
'urn:uma:variables:policyBaseIRI': `http://localhost:${cssPort}/`,
22+
'urn:uma:variables:policyDir': path.join(__dirname, '../../packages/uma/config/rules/policy'),
23+
'urn:uma:variables:eyePath': 'eye',
24+
}
25+
) as App;
26+
27+
cssApp = await instantiateFromConfig(
28+
'urn:solid-server:default:App',
29+
path.join(__dirname, '../../packages/css/config/default.json'),
30+
{
31+
...getDefaultCssVariables(cssPort),
32+
'urn:solid-server:uma:variable:AuthorizationServer': `http://localhost:${umaPort}/`,
33+
'urn:solid-server:default:variable:seedConfig': path.join(__dirname, '../../packages/css/config/seed.json'),
34+
},
35+
) as App;
36+
37+
await Promise.all([ umaApp.start(), cssApp.start() ]);
38+
});
39+
40+
afterAll(async(): Promise<void> => {
41+
await Promise.all([ umaApp.stop(), cssApp.stop() ]);
42+
});
43+
44+
describe('using public namespace authorization', (): void => {
45+
const container = `http://localhost:${cssPort}/alice/public/`;
46+
const slug = 'resource.txt';
47+
const body = 'This is a resource.';
48+
49+
it('RS: provides immediate read access.', async(): Promise<void> => {
50+
const publicResource = `http://localhost:${cssPort}/alice/profile/card`;
51+
52+
const publicResponse = await fetch(publicResource);
53+
54+
expect(publicResponse.status).toBe(200);
55+
expect(publicResponse.headers.get('content-type')).toBe('text/turtle');
56+
});
57+
58+
it('RS: provides immediate create access to the container', async(): Promise<void> => {
59+
const containerResponse = await fetch(container, {
60+
method: 'PUT',
61+
});
62+
expect(containerResponse.status).toBe(201);
63+
expect(containerResponse.headers.get('location')).toBe(container);
64+
});
65+
66+
it('RS: provides immediate create access to the contents', async(): Promise<void> => {
67+
const createResponse = await fetch(container, {
68+
method: 'POST',
69+
headers: { slug },
70+
body
71+
});
72+
expect(createResponse.status).toBe(201);
73+
expect(createResponse.headers.get('location')).toBe(`${container}${slug}`);
74+
});
75+
76+
it('RS: provides immediate read access to the contents', async(): Promise<void> => {
77+
const readResponse = await fetch(`${container}${slug}`);
78+
expect(readResponse.status).toBe(200);
79+
await expect(readResponse.text()).resolves.toBe(body);
80+
});
81+
82+
it('RS: provides immediate delete access to the contents', async(): Promise<void> => {
83+
const deleteResponse = await fetch(`${container}${slug}`, {
84+
method: 'DELETE',
85+
})
86+
expect(deleteResponse.status).toBe(205);
87+
88+
const readResponse = await fetch(`${container}${slug}`);
89+
expect(readResponse.status).toBe(404);
90+
});
91+
});
92+
93+
describe('using ODRL authorization', (): void => {
94+
const privateResource = `http://localhost:${cssPort}/alice/private/resource.txt`;
95+
let wwwAuthenticateHeader: string;
96+
let ticket: string;
97+
let tokenEndpoint: string;
98+
let jsonResponse: { access_token: string, token_type: string };
99+
100+
it('RS: sends a WWW-Authenticate response when access is private.', async(): Promise<void> => {
101+
const noTokenResponse = await fetch(privateResource, {
102+
method: 'PUT',
103+
body: 'Some text ...' ,
104+
});
105+
106+
expect(noTokenResponse.status).toBe(401);
107+
wwwAuthenticateHeader = noTokenResponse.headers.get('WWW-Authenticate');
108+
expect(typeof wwwAuthenticateHeader).toBe('string');
109+
});
110+
111+
it('AS: returns the token endpoint from the configuration.', async(): Promise<void> => {
112+
const parsedHeader = Object.fromEntries(
113+
wwwAuthenticateHeader
114+
.replace(/^UMA /,'')
115+
.split(', ')
116+
.map(param => param.split('=').map(s => s.replace(/"/g,'')))
117+
);
118+
expect(typeof parsedHeader.as_uri).toBe('string');
119+
expect(typeof parsedHeader.ticket).toBe('string');
120+
ticket = parsedHeader.ticket;
121+
122+
const configurationUrl = parsedHeader.as_uri + '/.well-known/uma2-configuration';
123+
const response = await fetch(configurationUrl);
124+
expect(response.status).toBe(200);
125+
const configuration = await response.json();
126+
expect(typeof configuration.token_endpoint).toBe('string');
127+
tokenEndpoint = configuration.token_endpoint;
128+
});
129+
130+
it('AS: responds with a token when receiving the ticket.', async(): Promise<void> => {
131+
const claim_token = 'https://woslabbi.pod.knows.idlab.ugent.be/profile/card#me';
132+
133+
const content = {
134+
grant_type: 'urn:ietf:params:oauth:grant-type:uma-ticket',
135+
ticket,
136+
claim_token: encodeURIComponent(claim_token),
137+
claim_token_format: 'urn:solidlab:uma:claims:formats:webid',
138+
};
139+
140+
const asRequestResponse = await fetch(tokenEndpoint, {
141+
method: 'POST',
142+
headers: { 'content-type': 'application/json' },
143+
body: JSON.stringify(content),
144+
});
145+
146+
expect(asRequestResponse.status).toBe(200);
147+
expect(asRequestResponse.headers.get('content-type')).toBe('application/json');
148+
jsonResponse = await asRequestResponse.json();
149+
expect(typeof jsonResponse.access_token).toBe('string');
150+
expect(jsonResponse.token_type).toBe('Bearer');
151+
const token = JSON.parse(Buffer.from(jsonResponse.access_token.split('.')[1], 'base64').toString());
152+
expect(Array.isArray(token.permissions)).toBe(true);
153+
expect(token.permissions).toHaveLength(2);
154+
expect(token.permissions).toContainEqual({
155+
resource_id: `http://localhost:${cssPort}/alice/private/resource.txt`,
156+
resource_scopes: [ 'urn:example:css:modes:append', 'urn:example:css:modes:create' ]
157+
});
158+
expect(token.permissions).toContainEqual({
159+
resource_id: `http://localhost:${cssPort}/alice/private/`,
160+
resource_scopes: [ 'urn:example:css:modes:create' ]
161+
}
162+
);
163+
});
164+
165+
it('RS: provides access when receiving a valid token.', async(): Promise<void> => {
166+
const response = await fetch(privateResource, {
167+
method: 'PUT',
168+
headers: { 'Authorization': `${jsonResponse.token_type} ${jsonResponse.access_token}` },
169+
body: 'Some text ...' ,
170+
});
171+
172+
expect(response.status).toBe(201);
173+
});
174+
});
175+
});

0 commit comments

Comments
 (0)