Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 14 additions & 40 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,31 +29,24 @@
"fix": "run-s fix:*",
"fix:prettier": "prettier --config .prettierrc \"src/**/*.{ts,css,less,scss,js}\" --write",
"fix:lint": "eslint src --ext .ts --fix",
"test": "run-s test:*",
"test:unit": "run-s build && ava --verbose 'build/tests/unit/**/*.spec.js'",
"test:integration": "run-s build && ava --verbose build/tests/endpoints/**/*.spec.js",
"test:module-imports": "run-s build && ava --verbose build/tests/module-imports/**/*.spec.js",
"test:e2e:rbac": "run-s build && ava --verbose build/tests/e2e/rbac.e2e.spec.js",
"test:e2e:rebac": "run-s build && ava --verbose build/tests/e2e/rebac.e2e.spec.js",
"test:e2e:local_facts": "run-s build && ava --verbose build/tests/e2e/local_facts.e2e.spec.js",
"test:ci:unit": "run-s test:unit test:module-imports",
"test:ci:full": "run-s test",
"test": "run-s build && vitest run --project unit --project module-imports && vitest run --project integration && vitest run --project e2e",
"test:unit": "vitest run --project unit",
"test:module-imports": "run-s build && vitest run --project module-imports",
"test:integration": "vitest run --project integration",
"test:e2e": "vitest run --project e2e",
"test:ci:unit": "run-s build && vitest run --project unit --project module-imports",
"test:ci:full": "run-s build && vitest run --project unit --project module-imports && vitest run --project integration && vitest run --project e2e",
"check-cli": "run-s test diff-integration-tests check-integration-tests",
"check-integration-tests": "run-s check-integration-test:*",
"diff-integration-tests": "mkdir -p diff && rm -rf diff/test && cp -r test diff/test && rm -rf diff/test/test-*/.git && cd diff && git init --quiet && git add -A && git commit --quiet --no-verify --allow-empty -m 'WIP' && echo '\\n\\nCommitted most recent integration test output in the \"diff\" directory. Review the changes with \"cd diff && git diff HEAD\" or your preferred git diff viewer.'",
"watch:build": "tsc -p tsconfig.json -w",
"watch:test": "nyc --silent ava --watch --verbose",
"cov": "run-s build test:unit cov:html cov:lcov && open-cli coverage/index.html",
"cov:html": "nyc report --reporter=html",
"cov:lcov": "nyc report --reporter=lcov",
"cov:send": "run-s cov:lcov && codecov",
"cov:check": "nyc report && nyc check-coverage --lines 100 --functions 100 --branches 100",
"watch": "vitest --project unit",
"coverage": "vitest run --project unit --coverage",
"docs": "typedoc",
"docs:watch": "typedoc --watch",
"version": "2.5.2",
"reset-hard": "git clean -dfx && git reset --hard && yarn",
"prepare": "npm run build && husky install",
"prepare-release": "run-s reset-hard test cov:check doc:html version doc:publish",
"prepare-release": "run-s reset-hard test doc:html version doc:publish",
"generate-openapi-client": "openapi-generator-cli generate -i https://api.permit.io/v2/openapi.json -g typescript-axios -o src/openapi/ --additional-properties=useSingleRequestParameter=true,withSeparateModelsAndApi=true,apiPackage=api,modelPackage=types --skip-validate-spec && yarn fix:prettier"
},
"engines": {
Expand All @@ -71,18 +64,15 @@
"url-parse": "^1.5.10"
},
"devDependencies": {
"@ava/typescript": "^1.1.1",
"@babel/traverse": "^7.24.8",
"@istanbuljs/nyc-config-typescript": "^1.0.1",
"@openapitools/openapi-generator-cli": "^2.5.2",
"@types/express": "^4.17.9",
"@types/lodash": "^4.14.166",
"@types/node": "^14.14.14",
"@types/node": "^20.14.0",
"@types/url-parse": "^1.4.11",
"@typescript-eslint/eslint-plugin": "^4.0.1",
"@typescript-eslint/parser": "^4.0.1",
"ava": "^3.12.1",
"codecov": "^3.5.0",
"@vitest/coverage-v8": "^4.1.0",
"cspell": "^4.1.0",
"cz-conventional-changelog": "^3.3.0",
"eslint": "^7.8.0",
Expand All @@ -94,14 +84,12 @@
"husky": "^7.0.0",
"lint-staged": "^12.1.2",
"npm-run-all": "^4.1.5",
"nyc": "^15.1.0",
"open-cli": "^8.0.0",
"prettier": "^2.5.1",
"standard-version": "^9.0.0",
"ts-node": "^9.0.0",
"tsup": "^8.5.0",
"typedoc": "^0.24.7",
"typescript": "^4.6.4"
"typescript": "^4.6.4",
"vitest": "^4.1.0"
},
"files": [
"build/**/*.d.ts",
Expand All @@ -112,14 +100,6 @@
"LICENSE",
"README.md"
],
"ava": {
"failFast": true,
"failWithoutAssertions": false,
"timeout": "60s",
"files": [
"!src/tests/fixtures.ts"
]
},
"lint-staged": {
"*.{ts,css,less,scss,js,html}": [
"prettier --config .prettierrc --write"
Expand All @@ -130,11 +110,5 @@
"path": "cz-conventional-changelog"
}
},
"nyc": {
"extends": "@istanbuljs/nyc-config-typescript",
"exclude": [
"**/*.spec.js"
]
},
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}
106 changes: 0 additions & 106 deletions src/tests/bulk_test.spec.ts

This file was deleted.

88 changes: 88 additions & 0 deletions src/tests/e2e/bulk.e2e.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import pino from 'pino';

import { IPermitClient } from '../../index';
import { createTestClient } from '../fixtures';

let permit: IPermitClient;
let logger: pino.Logger;

// Every user key this spec creates, so afterAll can purge them from the shared
// environment and not pollute sibling suites.
const CREATED_USER_KEYS = ['user_maya_test_1', 'user_maya_test_2', 'user_maya_1', 'user_maya_2'];

// Resources/relation backing the relationship-tuple test. Created here so the
// test is self-contained in a shared backend (rebac uses its own schema).
const FOLDERS_RESOURCE = 'folders';
const DOCS_RESOURCE = 'docs';

beforeAll(async () => {
({ permit, logger } = createTestClient());

await permit.api.resources
.create({ key: FOLDERS_RESOURCE, name: 'Folders', actions: { read: {} } })
.catch(() => null);
await permit.api.resources
.create({ key: DOCS_RESOURCE, name: 'Docs', actions: { read: {} } })
.catch(() => null);
// docs:<x> --parent--> folders:<y>; subject of the relation is a folder.
await permit.api.resourceRelations
.create(DOCS_RESOURCE, {
key: 'parent',
name: 'Parent',
subject_resource: FOLDERS_RESOURCE,
})
.catch(() => null);
});

afterAll(async () => {
if (!permit) return; // beforeAll never initialized the client (e.g. missing key)
// Purge every user this spec created.
await permit.api.users.bulkUserDelete(CREATED_USER_KEYS).catch(() => null);
// Deleting the resources cascades to their instances and relationship tuples.
await permit.api.resources.delete(DOCS_RESOURCE).catch(() => null);
await permit.api.resources.delete(FOLDERS_RESOURCE).catch(() => null);
});

it('Bulk relationship tuples test', async () => {
const tuples = [
{
subject: 'folders:pdf',
relation: 'parent',
object: 'docs:tasks',
tenant: 'default',
},
{
subject: 'folders:png',
relation: 'parent',
object: 'docs:files',
tenant: 'default',
},
];
logger.info('Tuples: ' + JSON.stringify(tuples));
const result = await permit.api.relationshipTuples.bulkRelationshipTuples(tuples);
expect(result).toBeDefined();
});

it('Bulk users test', async () => {
const users = [{ key: 'user_maya_test_1' }, { key: 'user_maya_test_2' }];
logger.info('users: ' + JSON.stringify(users));
await permit.api.users.bulkUserCreate(users);
});

it('Bulk users replace test', async () => {
const users = [
{ key: 'user_maya_test_1', first_name: '1' },
{ key: 'user_maya_test_2', first_name: '2' },
];
logger.info('users: ' + JSON.stringify(users));
await permit.api.users.bulkUserReplace(users);
});

it('Bulk users delete test', async () => {
const users = [{ key: 'user_maya_1' }, { key: 'user_maya_2' }];
logger.info('users: ' + JSON.stringify(users));
await permit.api.users.bulkUserCreate(users);
const users_key = ['user_maya_1', 'user_maya_2'];
logger.info('users: ' + JSON.stringify(users_key));
await permit.api.users.bulkUserDelete(users_key);
});
70 changes: 39 additions & 31 deletions src/tests/e2e/lists.e2e.spec.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,47 @@
import anyTest, { TestInterface } from 'ava';

import { printBreak, provideTestExecutionContext, TestContext } from '../fixtures';

const sleepTimeMs = 10000;

const test = anyTest as TestInterface<TestContext>;
test.before(provideTestExecutionContext);
test.before(async (t) => {
const permit = t.context.permit;
await permit.api.users
.bulkUserCreate(Array.from({ length: 10 }).map((_, i) => ({ key: `user-${i}` })))
.catch(() => null);
import { IPermitClient } from '../../index';
import { createTestClient } from '../fixtures';
import { waitFor } from '../helpers/wait-for';

let permit: IPermitClient;

// A run-unique prefix keeps these assertions scoped to the users this spec
// created, so they hold regardless of what other suites leave in the shared
// environment (no absolute-count assertions).
const PREFIX = `lists-${process.pid}-${Date.now()}`;
const USER_KEYS = Array.from({ length: 10 }).map((_, i) => `${PREFIX}-user-${i}`);

beforeAll(async () => {
({ permit } = createTestClient());
await permit.api.users.bulkUserCreate(USER_KEYS.map((key) => ({ key })));
// Bulk create is eventually consistent; gate until all 10 users are listable
// so the exact-count assertions below don't race the write propagating.
await waitFor(
async () => (await permit.api.users.list({ search: PREFIX, perPage: 100 })).total_count === 10,
{ timeoutMs: 60_000, intervalMs: 1_000, message: 'created users not yet listable' },
);
});

test('List users', async (t) => {
const permit = t.context.permit;

const users = await permit.api.users.list();
t.is(users.total_count, 10);
t.is(users.data.length, 10);
afterAll(async () => {
if (!permit) return; // beforeAll never initialized the client (e.g. missing key)
await permit.api.users.bulkUserDelete(USER_KEYS).catch(() => null);
});

test('List users with pagination', async (t) => {
const permit = t.context.permit;

const users = await permit.api.users.list({ page: 1, perPage: 5 });
t.is(users.total_count, 10);
t.is(users.data.length, 5);
it('List users scoped by prefix returns exactly the created users', async () => {
const users = await permit.api.users.list({ search: PREFIX });
expect(users.total_count).toBe(10);
expect(users.data.length).toBe(10);
});

test('List users with search', async (t) => {
const permit = t.context.permit;
it('List users with pagination over the scoped subset', async () => {
const users = await permit.api.users.list({ search: PREFIX, page: 1, perPage: 5 });
expect(users.total_count).toBe(10);
expect(users.data.length).toBe(5);
});

const users = await permit.api.users.list({ search: 'user-1' });
t.is(users.total_count, 1);
t.is(users.data.length, 1);
t.is(users.data[0].key, 'user-1');
it('List users searching a single full key returns one user', async () => {
const oneKey = USER_KEYS[0];
const users = await permit.api.users.list({ search: oneKey });
expect(users.total_count).toBe(1);
expect(users.data.length).toBe(1);
expect(users.data[0].key).toBe(oneKey);
});
Loading