test: add access-control int tests

This commit is contained in:
Elliot DeNolf
2022-07-18 18:50:27 -07:00
parent 2a7651eb9c
commit 6a9ea638d5
5 changed files with 171 additions and 14 deletions

View File

@@ -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,

View File

@@ -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();
});
});

View 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 ?? {},
});
}

View File

@@ -1,3 +0,0 @@
describe('array stuff', () => {
it.todo('should properly prevent / allow public users from reading a restricted field');
});

View File

@@ -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;
}