test: add access-control int tests
This commit is contained in:
@@ -1,28 +1,45 @@
|
||||
import { devUser } from '../credentials';
|
||||
import { buildConfig } from '../buildConfig';
|
||||
|
||||
export const slug = 'access-controls';
|
||||
export const slug = 'posts';
|
||||
export const readOnlySlug = 'read-only-collection';
|
||||
export const restrictedSlug = 'restricted';
|
||||
export const restrictedVersionsSlug = 'restricted-versions';
|
||||
|
||||
const openAccess = {
|
||||
create: () => true,
|
||||
read: () => true,
|
||||
update: () => true,
|
||||
delete: () => true,
|
||||
};
|
||||
|
||||
export default buildConfig({
|
||||
collections: [
|
||||
{
|
||||
slug,
|
||||
access: {
|
||||
...openAccess,
|
||||
update: () => false,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'restrictedField',
|
||||
type: 'text',
|
||||
access: {
|
||||
read: () => false,
|
||||
update: () => false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: restrictedSlug,
|
||||
fields: [],
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
access: {
|
||||
create: () => false,
|
||||
read: () => false,
|
||||
|
||||
@@ -22,7 +22,7 @@ describe('access control', () => {
|
||||
let page: Page;
|
||||
let url: AdminUrlUtil;
|
||||
let restrictedUrl: AdminUrlUtil;
|
||||
let readoOnlyUrl: AdminUrlUtil;
|
||||
let readOnlyUrl: AdminUrlUtil;
|
||||
let restrictedVersionsUrl: AdminUrlUtil;
|
||||
|
||||
beforeAll(async ({ browser }) => {
|
||||
@@ -30,7 +30,7 @@ describe('access control', () => {
|
||||
|
||||
url = new AdminUrlUtil(serverURL, slug);
|
||||
restrictedUrl = new AdminUrlUtil(serverURL, restrictedSlug);
|
||||
readoOnlyUrl = new AdminUrlUtil(serverURL, readOnlySlug);
|
||||
readOnlyUrl = new AdminUrlUtil(serverURL, readOnlySlug);
|
||||
restrictedVersionsUrl = new AdminUrlUtil(serverURL, restrictedVersionsSlug);
|
||||
|
||||
const context = await browser.newContext();
|
||||
@@ -108,12 +108,12 @@ describe('access control', () => {
|
||||
});
|
||||
|
||||
test('should have collection url', async () => {
|
||||
await page.goto(readoOnlyUrl.list);
|
||||
await expect(page).toHaveURL(readoOnlyUrl.list); // no redirect
|
||||
await page.goto(readOnlyUrl.list);
|
||||
await expect(page).toHaveURL(readOnlyUrl.list); // no redirect
|
||||
});
|
||||
|
||||
test('should not have "Create New" button', async () => {
|
||||
await page.goto(readoOnlyUrl.create);
|
||||
await page.goto(readOnlyUrl.create);
|
||||
await expect(page.locator('.collection-list__header a')).toHaveCount(0);
|
||||
});
|
||||
|
||||
@@ -123,12 +123,12 @@ describe('access control', () => {
|
||||
});
|
||||
|
||||
test('edit view should not have actions buttons', async () => {
|
||||
await page.goto(readoOnlyUrl.edit(existingDoc.id));
|
||||
await page.goto(readOnlyUrl.edit(existingDoc.id));
|
||||
await expect(page.locator('.collection-edit__collection-actions li')).toHaveCount(0);
|
||||
});
|
||||
|
||||
test('fields should be read-only', async () => {
|
||||
await page.goto(readoOnlyUrl.edit(existingDoc.id));
|
||||
await page.goto(readOnlyUrl.edit(existingDoc.id));
|
||||
await expect(page.locator('#field-name')).toBeDisabled();
|
||||
});
|
||||
});
|
||||
|
||||
142
test/access-control/int.spec.ts
Normal file
142
test/access-control/int.spec.ts
Normal file
@@ -0,0 +1,142 @@
|
||||
import mongoose from 'mongoose';
|
||||
import payload from '../../src';
|
||||
import { Forbidden } from '../../src/errors';
|
||||
import { initPayloadTest } from '../helpers/configHelpers';
|
||||
import { restrictedSlug, slug } from './config';
|
||||
import type { Restricted, Post } from './payload-types';
|
||||
|
||||
describe('Access Control', () => {
|
||||
let post1: Post;
|
||||
let restricted: Restricted;
|
||||
|
||||
beforeAll(async () => {
|
||||
await initPayloadTest({ __dirname });
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
post1 = await payload.create<Post>({
|
||||
collection: slug,
|
||||
data: { name: 'name' },
|
||||
});
|
||||
|
||||
restricted = await payload.create<Restricted>({
|
||||
collection: restrictedSlug,
|
||||
data: { name: 'restricted' },
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await mongoose.connection.dropDatabase();
|
||||
await mongoose.connection.close();
|
||||
await payload.mongoMemoryServer.stop();
|
||||
});
|
||||
|
||||
it.todo('should properly prevent / allow public users from reading a restricted field');
|
||||
|
||||
describe('Collections', () => {
|
||||
describe('restricted collection', () => {
|
||||
it('field without read access should not show', async () => {
|
||||
const { id } = await createDoc({ restrictedField: 'restricted' });
|
||||
|
||||
const retrievedDoc = await payload.findByID({ collection: slug, id, overrideAccess: false });
|
||||
|
||||
expect(retrievedDoc.restrictedField).toBeUndefined();
|
||||
});
|
||||
|
||||
it('field without read access should not show when overrideAccess: true', async () => {
|
||||
const { id, restrictedField } = await createDoc({ restrictedField: 'restricted' });
|
||||
|
||||
const retrievedDoc = await payload.findByID({ collection: slug, id, overrideAccess: true });
|
||||
|
||||
expect(retrievedDoc.restrictedField).toEqual(restrictedField);
|
||||
});
|
||||
|
||||
it('field without read access should not show when overrideAccess default', async () => {
|
||||
const { id, restrictedField } = await createDoc({ restrictedField: 'restricted' });
|
||||
|
||||
const retrievedDoc = await payload.findByID({ collection: slug, id });
|
||||
|
||||
expect(retrievedDoc.restrictedField).toEqual(restrictedField);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Override Access', () => {
|
||||
describe('Fields', () => {
|
||||
it('should allow overrideAccess: false', async () => {
|
||||
const req = async () => payload.update<Post>({
|
||||
collection: slug,
|
||||
id: post1.id,
|
||||
data: { restrictedField: restricted.id },
|
||||
overrideAccess: false, // this should respect access control
|
||||
});
|
||||
|
||||
await expect(req).rejects.toThrow(Forbidden);
|
||||
});
|
||||
|
||||
it('should allow overrideAccess: true', async () => {
|
||||
const doc = await payload.update<Post>({
|
||||
collection: slug,
|
||||
id: post1.id,
|
||||
data: { restrictedField: restricted.id },
|
||||
overrideAccess: true, // this should override access control
|
||||
});
|
||||
|
||||
expect(doc).toMatchObject({ id: post1.id });
|
||||
});
|
||||
|
||||
it('should allow overrideAccess by default', async () => {
|
||||
const doc = await payload.update<Post>({
|
||||
collection: slug,
|
||||
id: post1.id,
|
||||
data: { restrictedField: restricted.id },
|
||||
});
|
||||
|
||||
expect(doc).toMatchObject({ id: post1.id });
|
||||
});
|
||||
});
|
||||
|
||||
describe('Collections', () => {
|
||||
const updatedName = 'updated';
|
||||
|
||||
it('should allow overrideAccess: false', async () => {
|
||||
const req = async () => payload.update({
|
||||
collection: restrictedSlug,
|
||||
id: restricted.id,
|
||||
data: { name: updatedName },
|
||||
overrideAccess: false, // this should respect access control
|
||||
});
|
||||
|
||||
await expect(req).rejects.toThrow(Forbidden);
|
||||
});
|
||||
|
||||
it('should allow overrideAccess: true', async () => {
|
||||
const doc = await payload.update({
|
||||
collection: restrictedSlug,
|
||||
id: restricted.id,
|
||||
data: { name: updatedName },
|
||||
overrideAccess: true, // this should override access control
|
||||
});
|
||||
|
||||
expect(doc).toMatchObject({ id: restricted.id, name: updatedName });
|
||||
});
|
||||
|
||||
it('should allow overrideAccess by default', async () => {
|
||||
const doc = await payload.update({
|
||||
collection: restrictedSlug,
|
||||
id: restricted.id,
|
||||
data: { name: updatedName },
|
||||
});
|
||||
|
||||
expect(doc).toMatchObject({ id: restricted.id, name: updatedName });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
async function createDoc(data: Partial<Post>): Promise<Post> {
|
||||
return payload.create({
|
||||
collection: slug,
|
||||
data: data ?? {},
|
||||
});
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
describe('array stuff', () => {
|
||||
it.todo('should properly prevent / allow public users from reading a restricted field');
|
||||
});
|
||||
@@ -8,9 +8,9 @@
|
||||
export interface Config {}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "access-controls".
|
||||
* via the `definition` "posts".
|
||||
*/
|
||||
export interface AccessControl {
|
||||
export interface Post {
|
||||
id: string;
|
||||
restrictedField?: string;
|
||||
createdAt: string;
|
||||
@@ -22,6 +22,7 @@ export interface AccessControl {
|
||||
*/
|
||||
export interface Restricted {
|
||||
id: string;
|
||||
name?: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user