Skip to content

Commit

Permalink
Story #8: implement canDelete property
Browse files Browse the repository at this point in the history
  • Loading branch information
ayashkov committed Oct 22, 2023
1 parent e3cafbd commit 8af79e7
Show file tree
Hide file tree
Showing 4 changed files with 227 additions and 7 deletions.
69 changes: 69 additions & 0 deletions src/lib/accessor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,75 @@ describe('Accessor', () => {
});
});

describe('#canDelete', () => {
it('is true when no methods array', () => {
const noMethods = new Accessor({
_client: spectator.httpClient,
_links: {
self: { href: '/api/v1/items' }
}
});

expect(noMethods.canDelete).toBe(true);
});

it('is true when methods is not an array', () => {
const notArray = new Accessor({
_client: spectator.httpClient,
_links: {
self: {
href: '/api/v1/items',
methods: 'GET'
}
}
});

expect(notArray.canDelete).toBe(true);
});

it('is false when no POST in methods array', () => {
const noPost = new Accessor({
_client: spectator.httpClient,
_links: {
self: {
href: '/api/v1/items',
methods: ['GET']
}
}
});

expect(noPost.canDelete).toBe(false);
});

it('is true when DELETE is in methods array', () => {
const withPost = new Accessor({
_client: spectator.httpClient,
_links: {
self: {
href: '/api/v1/items',
methods: ['GET', 'DELETE', 'PUT']
}
}
});

expect(withPost.canDelete).toBe(true);
});

it('is true when DELETE matches case insensitively', () => {
const withPost = new Accessor({
_client: spectator.httpClient,
_links: {
self: {
href: '/api/v1/items',
methods: [null, 'DeLeTe']
}
}
});

expect(withPost.canDelete).toBe(true);
});
});

describe('#delete()', () => {
it('deletes resource at self link', () => {
let next = false;
Expand Down
69 changes: 69 additions & 0 deletions src/lib/collection.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,75 @@ describe('Collection', () => {
});
});

describe('#canDelete', () => {
it('is true when no methods array', () => {
const noMethods = new Collection(TestResource, {
_client: spectator.httpClient,
_links: {
self: { href: '/api/v1/items' }
}
});

expect(noMethods.canDelete).toBe(true);
});

it('is true when methods is not an array', () => {
const notArray = new Collection(TestResource, {
_client: spectator.httpClient,
_links: {
self: {
href: '/api/v1/items',
methods: 'GET'
}
}
});

expect(notArray.canDelete).toBe(true);
});

it('is false when no POST in methods array', () => {
const noPost = new Collection(TestResource, {
_client: spectator.httpClient,
_links: {
self: {
href: '/api/v1/items',
methods: ['GET']
}
}
});

expect(noPost.canDelete).toBe(false);
});

it('is true when DELETE is in methods array', () => {
const withPost = new Collection(TestResource, {
_client: spectator.httpClient,
_links: {
self: {
href: '/api/v1/items',
methods: ['GET', 'DELETE', 'PUT']
}
}
});

expect(withPost.canDelete).toBe(true);
});

it('is true when DELETE matches case insensitively', () => {
const withPost = new Collection(TestResource, {
_client: spectator.httpClient,
_links: {
self: {
href: '/api/v1/items',
methods: [null, 'DeLeTe']
}
}
});

expect(withPost.canDelete).toBe(true);
});
});

describe('#delete()', () => {
it('deletes resource at self link when it exists', () => {
let next = false;
Expand Down
27 changes: 20 additions & 7 deletions src/lib/hal-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,19 @@ export abstract class HalBase {

/**
* This property is true when either `methods` array does not exist
* in the `self` link or the array exists and contains `POST` method.
* in the `self` link or the array exists and contains `POST` string.
*/
get canCreate(): boolean {
const methods = this._links[self]?.methods;

if (!Array.isArray(methods))
return true;
return this.can('POST');
}

return !!methods.find(method => typeof method === 'string' &&
method.toUpperCase() === 'POST');
/**
* This property is true when either `methods` array does not exist
* in the `self` link or the array exists and contains `DELETE`
* string.
*/
get canDelete(): boolean {
return this.can('DELETE');
}

/**
Expand Down Expand Up @@ -138,4 +141,14 @@ export abstract class HalBase {
...err.error
}));
}

private can(method: string): boolean {
const methods = this._links[self]?.methods;

if (!Array.isArray(methods))
return true;

return !!methods.find(m => typeof m === 'string' &&
m.toUpperCase() === method);
}
}
69 changes: 69 additions & 0 deletions src/lib/resource.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,75 @@ describe('Resource', () => {
});
});

describe('#canDelete', () => {
it('is true when no methods array', () => {
const noMethods = new Resource({
_client: spectator.httpClient,
_links: {
self: { href: '/api/v1/items' }
}
});

expect(noMethods.canDelete).toBe(true);
});

it('is true when methods is not an array', () => {
const notArray = new Resource({
_client: spectator.httpClient,
_links: {
self: {
href: '/api/v1/items',
methods: 'GET'
}
}
});

expect(notArray.canDelete).toBe(true);
});

it('is false when no POST in methods array', () => {
const noPost = new Resource({
_client: spectator.httpClient,
_links: {
self: {
href: '/api/v1/items',
methods: ['GET']
}
}
});

expect(noPost.canDelete).toBe(false);
});

it('is true when DELETE is in methods array', () => {
const withPost = new Resource({
_client: spectator.httpClient,
_links: {
self: {
href: '/api/v1/items',
methods: ['GET', 'DELETE', 'PUT']
}
}
});

expect(withPost.canDelete).toBe(true);
});

it('is true when DELETE matches case insensitively', () => {
const withPost = new Resource({
_client: spectator.httpClient,
_links: {
self: {
href: '/api/v1/items',
methods: [null, 'DeLeTe']
}
}
});

expect(withPost.canDelete).toBe(true);
});
});

describe('#delete()', () => {
it('deletes resource at self link when it exists', () => {
let next = false;
Expand Down

0 comments on commit 8af79e7

Please sign in to comment.