Skip to content
Closed
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
3,094 changes: 2,698 additions & 396 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"build:docs": "npx @redocly/cli build-docs -o docs/index.html admin@v1",
"watch:docs": "npx @redocly/cli preview-docs admin@v1",
"lint": "eslint .",
"test": "c8 mocha --spec=test/**/*.test.js",
"test": "vitest run --coverage",
"dev": "wrangler dev",
"deploy:prod": "wrangler deploy",
"deploy:stage": "wrangler deploy --env stage",
Expand All @@ -22,6 +22,7 @@
"devDependencies": {
"@adobe/eslint-config-helix": "2.0.6",
"@redocly/cli": "^1.4.1",
"@vitest/coverage-v8": "^3.2.4",
"aws-sdk-client-mock": "^4.0.0",
"c8": "^8.0.1",
"eslint": "8.56.0",
Expand All @@ -37,6 +38,7 @@
"@aws-sdk/client-s3": "^3.456.0",
"@aws-sdk/s3-request-presigner": "^3.468.0",
"@ssttevee/cfw-formdata-polyfill": "^0.2.1",
"jose": "^6.0.10"
"jose": "^6.0.10",
"vitest": "^3.2.4"
}
}
2 changes: 2 additions & 0 deletions test/handlers/get.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
*/
import assert from 'assert';

import { describe, it } from 'vitest';

import getHandler from '../../src/handlers/get.js';

describe('Get Route', () => {
Expand Down
2 changes: 2 additions & 0 deletions test/handlers/post.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
*/
import assert from 'assert';

import { describe, it } from 'vitest';

import postHandler from '../../src/handlers/post.js';

describe('Post Route', () => {
Expand Down
2 changes: 2 additions & 0 deletions test/handlers/unknown.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import assert from 'assert';
import unknownHandler from '../../src/handlers/unknown.js';

import { describe, it } from 'vitest';

describe('unknownHandler', () => {
it('should return unknown response', async () => {
const result = await unknownHandler({});
Expand Down
2 changes: 2 additions & 0 deletions test/helpers/source.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import assert from 'assert';
import putHelper from '../../src/helpers/source.js';

import { describe, it } from 'vitest';

import env from '../utils/mocks/env.js';
const daCtx = { org: 'cq', key: 'geometrixx/hello.html', propsKey: 'geometrixx/hello.html.props' };

Expand Down
39 changes: 20 additions & 19 deletions test/index.test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
import assert from 'assert';
import esmock from 'esmock';
import { describe, it, beforeAll, afterEach, vi } from 'vitest';
import handler from '../src/index.js';
import daCtx from '../src/utils/daCtx.js';

describe('fetch', () => {
beforeAll(() => {
vi.mock('../src/utils/daCtx.js', () => ({
default: vi.fn()
}));
});

afterEach(() => {
vi.resetAllMocks();
});

it('should be callable', () => {
assert(handler.fetch);
});
Expand All @@ -13,33 +24,23 @@ describe('fetch', () => {
});

it('should return a response object for unknown', async () => {
daCtx.mockImplementation(async () => ({ authorized: true, users: [{ email: 'test@example.com' }] }));

const resp = await handler.fetch({ url: 'https://www.example.com', method: 'BLAH' }, {});
assert.strictEqual(resp.status, 501);
});

it('should return 401 when not authorized and not logged in', async () => {
const hnd = await esmock(
'../src/index.js', {
'../src/utils/daCtx.js': {
default: async () => ({ authorized: false, users: [{ email: 'anonymous' }] })
}
}
)

const resp = await hnd.fetch({ method: 'GET' }, {});
daCtx.mockImplementation(async () => ({ authorized: false, users: [{ email: 'anonymous' }] }));

const resp = await handler.fetch({ method: 'GET' }, {});
assert.strictEqual(resp.status, 401);
});

it('should return 403 when logged in but not authorized', async () => {
const hnd = await esmock(
'../src/index.js', {
'../src/utils/daCtx.js': {
default: async () => ({ authorized: false, users: [{ email: 'joe@bloggs.org' }] })
}
}
)

const resp = await hnd.fetch({ method: 'GET' }, {});
daCtx.mockImplementation(async () => ({ authorized: false, users: [{ email: 'joe@bloggs.org' }] }));

const resp = await handler.fetch({ method: 'GET' }, {});
assert.strictEqual(resp.status, 403);
});
});
114 changes: 35 additions & 79 deletions test/routes/config.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,112 +9,68 @@
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
import assert from 'assert';
import esmock from 'esmock';
import { describe, it, afterEach, vi, expect, beforeAll } from 'vitest';

import { getConfig, postConfig } from '../../src/routes/config.js';
import { hasPermission } from '../../src/utils/auth.js';
import putKv from "../../src/storage/kv/put.js";
import getKv from "../../src/storage/kv/get.js";

describe('Config', () => {
beforeAll(() => {
vi.mock('../../src/storage/kv/get.js', () => ({
default: vi.fn(() => { return 'called' })
}));
vi.mock('../../src/storage/kv/put.js', () => ({
default: vi.fn(() => { return 'called' })
}));
vi.mock('../../src/utils/auth.js', () => ({
hasPermission: vi.fn()
}));
});

afterEach(() => {
vi.restoreAllMocks();
});

it('Test postConfig has permission', async () => {
const ctx = {};
const env = {};
const req = {};

const putKVCalled = []
const putKV = async (r, q, c) => {
putKVCalled.push({r, q, c});
return 'called';
};

const hasPermission = (c, k, a, kw) => {
if (k === 'CONFIG' && a === 'write' && kw === true) {
return true;
}
};

const { postConfig } = await esmock(
'../../src/routes/config.js', {
'../../src/storage/kv/put.js': {
default: putKV,
},
'../../src/utils/auth.js': {
hasPermission,
}
}
);
hasPermission.mockImplementationOnce((c, k, a, kw) => k === 'CONFIG' && a === 'write' && kw === true);

const res = await postConfig({ req, env, daCtx: ctx });
assert.strictEqual(res, 'called');
assert.deepStrictEqual(putKVCalled, [{r: req, q: env, c: ctx}]);
expect(hasPermission).toHaveBeenCalled();
expect(res).to.eq('called');
expect(putKv).toHaveBeenCalledWith(req, env, ctx);
});

it('Test getConfig has permission', async () => {
const ctx = {};
const env = {};
const req = {};

const getKVCalled = []
const getKV = async (e, c) => {
getKVCalled.push({e, c});
return 'called';
};

const hasPermission = (c, k, a, kw) => {
if (k === 'CONFIG' && a === 'read' && kw === true) {
return true;
}
};

const { getConfig } = await esmock(
'../../src/routes/config.js', {
'../../src/storage/kv/get.js': {
default: getKV,
},
'../../src/utils/auth.js': {
hasPermission,
}
}
);
hasPermission.mockImplementationOnce((c, k, a, kw) => k === 'CONFIG' && a === 'read' && kw === true);

const res = await getConfig({ env, daCtx: ctx });
assert.strictEqual(res, 'called');
assert.deepStrictEqual(getKVCalled, [{e: env, c: ctx}]);
expect(hasPermission).toHaveBeenCalled();
expect(res).to.eq('called');
expect(getKv).toHaveBeenCalledWith(env, ctx);
});

it('Test no permission', async () => {
const ctx = {};
const env = {};
const req = {};

const putKVCalled = []
const putKV = async (r, e, c) => {
putKVCalled.push({r, e, c});
};
const getKVCalled = []
const getKV = async (e, c) => {
getKVCalled.push({e, c});
};

const hasPermission = () => false;

const { getConfig, postConfig } = await esmock(
'../../src/routes/config.js', {
'../../src/storage/kv/get.js': {
default: getKV,
},
'../../src/storage/kv/put.js': {
default: putKV,
},
'../../src/utils/auth.js': {
hasPermission,
}
}
);
hasPermission.mockImplementationOnce(() => false);

const res = await getConfig({ env, daCtx: ctx });
assert.strictEqual(getKVCalled.length, 0, "Should not have read permission on config");
assert.strictEqual(res.status, 403);
expect(getKv).not.toHaveBeenCalled();
expect(res.status).to.eq(403);

const res2 = await postConfig({ req, env, daCtx: ctx });
assert.strictEqual(res2.status, 403);
assert.strictEqual(putKVCalled.length, 0);
expect(putKv).not.toHaveBeenCalled();
expect(res2.status).to.eq(403);
});
});
61 changes: 32 additions & 29 deletions test/routes/copy.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,38 @@
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
import assert from 'assert';
import esmock from 'esmock';
import { describe, it, afterEach, vi, expect, beforeAll } from 'vitest';
import copyHandler from '../../src/routes/copy.js';
import copy from '../../src/storage/object/copy.js';
import { hasPermission } from "../../src/utils/auth.js";

describe('Copy Route', () => {

beforeAll(() => {
vi.mock('../../src/storage/object/copy.js', () => ({
default: vi.fn(),
}))
vi.mock('../../src/utils/auth.js', () => ({
hasPermission: vi.fn(),
}))
});

afterEach(() => {
vi.resetAllMocks();
})

it('Test copyHandler with permissions', async () => {
const copyCalled = [];
const copyObject = (e, c, d, m) => {
copyCalled.push({e, c, d, m});
return { status: 200 };
};
copy.mockImplementation(() => ({ status: 200 }));

const hasPermission = (c, k, a) => {
hasPermission.mockImplementation((c, k, a) => {
if (k === 'my/src.html' && a === 'read') {
return false;
}
if (k === 'my/dest.html' && a === 'write') {
return false;
}
return true;
}
const copyHandler = await esmock(
'../../src/routes/copy.js', {
'../../src/storage/object/copy.js': {
default: copyObject
},
'../../src/utils/auth.js': {
hasPermission }
}
);
});

const formdata = new Map();
formdata.set('destination', '/myorg/MY/dest.html')
Expand All @@ -46,12 +49,12 @@ describe('Copy Route', () => {
};

const resp = await copyHandler({ req, env: {}, daCtx: { key: 'my/src.html' }});
assert.strictEqual(403, resp.status);
assert.strictEqual(copyCalled.length, 0);
expect(resp.status).to.eq(403);
expect(copy).not.toHaveBeenCalled();

const resp2 = await copyHandler({ req, env: {}, daCtx: { key: 'my/src2.html' }});
assert.strictEqual(403, resp2.status);
assert.strictEqual(copyCalled.length, 0);
expect(resp2.status).to.eq(403);
expect(copy).not.toHaveBeenCalled();

const formdata2 = new Map();
formdata2.set('destination', '/myorg/MY/dest2.html')
Expand All @@ -60,14 +63,14 @@ describe('Copy Route', () => {
};

const resp3 = await copyHandler({ req: req2, env: {}, daCtx: { key: 'my/src.html' }});
assert.strictEqual(403, resp3.status);
assert.strictEqual(copyCalled.length, 0);
expect(resp3.status).to.eq(403);
expect(copy).not.toHaveBeenCalled();

const resp4 = await copyHandler({ req: req2, env: {}, daCtx: { key: 'my/src2.html' }});
assert.strictEqual(200, resp4.status);
assert.strictEqual(copyCalled.length, 1);
assert.strictEqual('my/src2.html', copyCalled[0].d.source);
assert.strictEqual('my/dest2.html', copyCalled[0].d.destination);
assert.strictEqual(false, copyCalled[0].m);
expect(resp4.status).to.eq(200);
expect(copy).toHaveBeenCalled();
expect(copy.mock.calls[0][2].source).to.eq('my/src2.html');
expect(copy.mock.calls[0][2].destination).to.eq('my/dest2.html');
expect(copy.mock.calls[0][3]).to.be.false;
});
});
Loading