Skip to content

Commit

Permalink
test: adds test that ensures ForbiddenError default error message use…
Browse files Browse the repository at this point in the history
…s subject type name
  • Loading branch information
stalniy committed Oct 29, 2022
1 parent c75d94a commit 546bc6e
Show file tree
Hide file tree
Showing 9 changed files with 104 additions and 70 deletions.
2 changes: 1 addition & 1 deletion packages/casl-ability/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"prebuild": "rm -rf dist/*",
"build": "npm run build.types && npm run build.core && npm run build.extra",
"lint": "dx eslint src/ spec/",
"test": "dx jest --config ../dx/config/jest.chai.config.js",
"test": "dx jest",
"prerelease": "npm run lint && npm test && NODE_ENV=production npm run build",
"release": "dx semantic-release",
"preb": "echo 'pre'",
Expand Down
65 changes: 0 additions & 65 deletions packages/casl-ability/spec/error.spec.js

This file was deleted.

91 changes: 91 additions & 0 deletions packages/casl-ability/spec/error.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { ForbiddenError, getDefaultErrorMessage, PureAbility, SubjectType } from '../src'

describe('`ForbiddenError` class', () => {
describe('`throwUnlessCan` method', () => {
it('raises forbidden exception on disallowed action', () => {
const { error } = setup()
expect(() => error.throwUnlessCan('archive', 'Post')).toThrow(ForbiddenError as unknown as Error)
})

it('does not raise forbidden exception on allowed action', () => {
const { error } = setup()
expect(() => error.throwUnlessCan('read', 'Post')).not.toThrow(ForbiddenError as unknown as Error)
})

it('raises error with context information', () => {
let thrownError: ForbiddenError<PureAbility> | undefined
const { error } = setup()

try {
error.throwUnlessCan('archive', 'Post')
} catch (abilityError) {
thrownError = abilityError as ForbiddenError<PureAbility>
}

expect(thrownError!.action).toBe('archive')
expect(thrownError!.subject).toBe('Post')
expect(thrownError!.subjectType).toBe('Post')
})

it('raises error with message provided in `reason` field of forbidden rule', () => {
const NO_CARD_MESSAGE = 'No credit card provided'
const { ability, error } = setup()

ability.update([{
action: 'update',
subject: 'Post',
inverted: true,
reason: NO_CARD_MESSAGE
}])

expect(() => error.throwUnlessCan('update', 'Post')).toThrow(NO_CARD_MESSAGE)
})

it('can raise error with custom message', () => {
const message = 'My custom error message'
const { error } = setup()

expect(() => error.setMessage(message).throwUnlessCan('update', 'Post')).toThrow(message)
})

it('correctly extracts subject type name from class subject types', () => {
class Post {}

const ability = new PureAbility([
{ action: 'read', subject: Post }
], {
detectSubjectType: o => o.constructor as SubjectType
})

try {
ForbiddenError.from(ability).throwUnlessCan('update', Post)
expect('this code').toBe('never reached')
} catch (error) {
expect((error as ForbiddenError<PureAbility>).subjectType).toBe('Post')
expect((error as ForbiddenError<PureAbility>).message).toBe('Cannot execute "update" on "Post"')
}
})
})

describe('`setDefaultMessage` method', () => {
afterEach(() => {
ForbiddenError.setDefaultMessage(getDefaultErrorMessage)
})

it('sets default message from function', () => {
ForbiddenError.setDefaultMessage(err => `errror -> ${err.action}-${err.subjectType}`)
const { error } = setup()

expect(() => error.throwUnlessCan('update', 'Post')).toThrow('errror -> update-Post')
})
})

function setup() {
const ability = new PureAbility([
{ action: 'read', subject: 'Post' }
])
const error = ForbiddenError.from(ability)

return { ability, error }
}
})
1 change: 1 addition & 0 deletions packages/casl-ability/spec/pack_rules.spec.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import './spec_helper';
import { packRules, unpackRules } from '../src/extra'

describe('Ability rules packing', () => {
Expand Down
1 change: 1 addition & 0 deletions packages/casl-ability/spec/rulesToAST.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { defineAbility } from '../src'
import { rulesToAST } from '../src/extra'
import './spec_helper';

describe('rulesToAST', () => {
it('returns empty "and" `Condition` if there are no conditions in `Ability`', () => {
Expand Down
1 change: 1 addition & 0 deletions packages/casl-ability/spec/rulesToQuery.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { defineAbility } from '../src'
import { rulesToQuery } from '../src/extra'
import './spec_helper';

function toQuery(ability, action, subject) {
const convert = rule => rule.inverted ? { $not: rule.conditions } : rule.conditions
Expand Down
1 change: 1 addition & 0 deletions packages/casl-ability/spec/rules_to_fields.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { rulesToFields } from '../src/extra'
import { defineAbility, PureAbility } from '../src'
import './spec_helper';

describe('rulesToFields', () => {
it('returns an empty object for an empty `Ability` instance', () => {
Expand Down
1 change: 1 addition & 0 deletions packages/casl-ability/spec/spec_helper.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import chai from 'chai'
import spies from 'chai-spies'
import '../../dx/lib/spec_helper';

chai.use(spies)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,23 @@ import { subject, detectSubjectType } from '../src'
describe('`subject` helper', () => {
it('defines subject type for an object', () => {
const object = subject('Article', {})
expect(detectSubjectType(object)).to.equal('Article')
expect(detectSubjectType(object)).toBe('Article')
})

it('throws exception when trying to redefine subject type', () => {
const object = subject('Article', {})
expect(() => subject('User', object)).to.throw(Error)
expect(() => subject('User', object)).toThrow(Error)
})

it('does not throw if subject type of an object equals to provided subject type', () => {
const object = subject('Article', {})
expect(() => subject('Article', object)).not.to.throw(Error)
expect(() => subject('Article', object)).not.toThrow(Error)
})

it('ignores falsy subjects', () => {
expect(() => subject('Test', null)).not.to.throw(Error)
// @ts-expect-error
expect(() => subject('Test', null)).not.toThrow(Error)
// @ts-expect-error
expect(() => subject('Test', undefined)).not.toThrow(Error)
})
})

0 comments on commit 546bc6e

Please sign in to comment.