@eturino/claims
Version:
Claim, ClaimSet and Ability for permissions (Typescript port of https://github.com/eturino/claims)
595 lines (467 loc) • 18.9 kB
text/typescript
import { describe, expect, it } from "vitest";
import { ALLOWED_VERBS, type AllowedVerb } from "../../..";
import { Claim, type IClaimData, buildClaim, extractVerbResource } from "../claim";
import { isValidClaimString } from "../is-valid-claim-string";
describe("new Claim()", () => {
it("fails with wrong verb", () => {
expect(() => new Claim({ verb: "bad" as AllowedVerb, resource: "resource" })).toThrowError();
});
});
describe("Claim#clone", () => {
it("makes a clone", () => {
const original = buildClaim("read:*");
const cloned = original.clone();
expect(cloned).not.toBe(original);
expect(cloned).toEqual(original);
});
});
describe("buildClaim()", () => {
it("with empty string: error", async () => {
expect(() => buildClaim("")).toThrowError();
});
it("with 'blah:what': error", async () => {
expect(() => buildClaim("blah:what")).toThrowError();
});
it("with 'blah:*': error", async () => {
expect(() => buildClaim("blah:*")).toThrowError();
});
for (const verb of ALLOWED_VERBS) {
it(`with '${verb}:what': builds Claim (${verb}: what)`, async () => {
const claim = buildClaim(`${verb}:what`);
expect(claim).toBeInstanceOf(Claim);
expect(claim.verb).toEqual(verb);
expect(claim.hasVerb(verb)).toBeTruthy();
expect(claim.resource).toEqual("what");
expect(claim.isGlobal()).toBeFalsy();
});
}
it("with 'admin:what': builds Claim (admin: what)", async () => {
const claim = buildClaim("admin:what");
expect(claim).toBeInstanceOf(Claim);
expect(claim.verb).toEqual("admin");
expect(claim.hasVerb("admin")).toBeTruthy();
expect(claim.resource).toEqual("what");
expect(claim.isGlobal()).toBeFalsy();
});
it("with 'admin:what.*': builds Claim (admin: what)", async () => {
const claim = buildClaim("admin:what.*");
expect(claim).toBeInstanceOf(Claim);
expect(claim.verb).toEqual("admin");
expect(claim.hasVerb("admin")).toBeTruthy();
expect(claim.resource).toEqual("what");
expect(claim.isGlobal()).toBeFalsy();
});
it("with 'admin:*': builds Claim (global admin)", async () => {
const claim = buildClaim("admin:*");
expect(claim).toBeInstanceOf(Claim);
expect(claim.verb).toEqual("admin");
expect(claim.hasVerb("admin")).toBeTruthy();
expect(claim.resource).toBeNull();
expect(claim.isGlobal()).toBeTruthy();
});
it("with 'read:what': builds Claim (read: what)", async () => {
const claim = buildClaim("read:what");
expect(claim).toBeInstanceOf(Claim);
expect(claim.verb).toEqual("read");
expect(claim.hasVerb("read")).toBeTruthy();
expect(claim.resource).toEqual("what");
expect(claim.isGlobal()).toBeFalsy();
});
it("with 'read:what.*': builds Claim (read: what)", async () => {
const claim = buildClaim("read:what.*");
expect(claim).toBeInstanceOf(Claim);
expect(claim.verb).toEqual("read");
expect(claim.hasVerb("read")).toBeTruthy();
expect(claim.resource).toEqual("what");
expect(claim.isGlobal()).toBeFalsy();
});
it("with 'read:*': builds Claim (global read)", async () => {
const claim = buildClaim("read:*");
expect(claim).toBeInstanceOf(Claim);
expect(claim.verb).toEqual("read");
expect(claim.hasVerb("read")).toBeTruthy();
expect(claim.resource).toBeNull();
expect(claim.isGlobal()).toBeTruthy();
});
});
describe("Claim#check()", () => {
describe('buildClaim("read:*")', () => {
const claim = buildClaim("read:*");
it(".check('invalid:*'): error", async () => {
expect(() => claim.check("invalid:*")).toThrowError();
});
it(".check('read:*'): true", async () => {
expect(claim.check("read:*")).toBeTruthy();
});
it(".check('read:something.else'): true", async () => {
expect(claim.check("read:something.else")).toBeTruthy();
});
it(".check('admin:*'): false", async () => {
expect(claim.check("admin:*")).toBeFalsy();
});
});
describe('buildClaim("read:something")', () => {
const claim = buildClaim("read:something");
it(".check('read:*'): false", async () => {
expect(claim.check("read:*")).toBeFalsy();
});
it(".check('read:something'): true", async () => {
expect(claim.check("read:something")).toBeTruthy();
});
it(".check('read:something.else'): true", async () => {
expect(claim.check("read:something.else")).toBeTruthy();
});
it(".check('admin:*'): false", async () => {
expect(claim.check("admin:*")).toBeFalsy();
});
it(".check('admin:something'): false", async () => {
expect(claim.check("admin:something")).toBeFalsy();
});
});
});
describe("Claim#toString()", () => {
describe("global (read:*)", () => {
it('returns "read:*"', () => {
const claim = buildClaim("read:*");
expect(claim.toString()).toEqual("read:*");
});
});
describe("not global (read:something.or.other)", () => {
it('returns "read:*"', () => {
const claim = buildClaim("read:something.or.other");
expect(claim.toString()).toEqual("read:something.or.other");
});
});
});
describe("Claim#isExact()", () => {
describe('buildClaim("read:*")', () => {
const claim = buildClaim("read:*");
it(".isExact('invalid:*'): error", async () => {
expect(() => claim.isExact("invalid:*")).toThrowError();
});
it(".isExact('read:*'): true", async () => {
expect(claim.isExact("read:*")).toBeTruthy();
});
it(".isExact('read:something.else'): false", async () => {
expect(claim.isExact("read:something.else")).toBeFalsy();
});
it(".isExact('admin:*'): false", async () => {
expect(claim.isExact("admin:*")).toBeFalsy();
});
});
describe('buildClaim("read:something")', () => {
const claim = buildClaim("read:something");
it(".isExact('read:*'): false", async () => {
expect(claim.isExact("read:*")).toBeFalsy();
});
it(".isExact('read:something'): true", async () => {
expect(claim.isExact("read:something")).toBeTruthy();
});
it(".isExact('read:something.else'): false", async () => {
expect(claim.isExact("read:something.else")).toBeFalsy();
});
it(".isExact('admin:*'): false", async () => {
expect(claim.isExact("admin:*")).toBeFalsy();
});
it(".isExact('admin:something'): false", async () => {
expect(claim.isExact("admin:something")).toBeFalsy();
});
});
});
describe("Claim#directChild()", () => {
describe('buildClaim("read:*")', () => {
const claim = buildClaim("read:*");
it(".directChild('invalid:*'): error", async () => {
expect(() => claim.directChild("invalid:*")).toThrowError();
});
it(".directChild('read:*'): null", async () => {
expect(claim.directChild("read:*")).toBeNull();
});
it(".directChild('read:something.else'): null", async () => {
expect(claim.directChild("read:something.else")).toBeNull();
});
it(".directChild('admin:*'): null", async () => {
expect(claim.directChild("admin:*")).toBeNull();
});
});
describe('buildClaim("read:something")', () => {
const claim = buildClaim("read:something");
it(".directChild('read:*'): 'something'", async () => {
expect(claim.directChild("read:*")).toEqual("something");
});
it(".directChild('read:something'): null", async () => {
expect(claim.directChild("read:something")).toBeNull();
});
it(".directChild('read:something.else'): null", async () => {
expect(claim.directChild("read:something.else")).toBeNull();
});
it(".directChild('read:another.else'): false", async () => {
expect(claim.directChild("read:another.else")).toBeNull();
});
it(".directChild('admin:*'): null", async () => {
expect(claim.directChild("admin:*")).toBeNull();
});
it(".directChild('admin:something'): null", async () => {
expect(claim.directChild("admin:something")).toBeNull();
});
});
describe('buildClaim("read:what.some.stuff")', () => {
const claim = buildClaim("read:what.some.stuff");
it(".directChild('read:*'): null", async () => {
expect(claim.directChild("read:*")).toBeNull();
});
it(".directChild('read:what'): null", async () => {
expect(claim.directChild("read:what")).toBeNull();
});
it(".directChild('read:what.some'): stuff", async () => {
expect(claim.directChild("read:what.some")).toEqual("stuff");
});
it(".directChild('read:what.some.stuff'): null", async () => {
expect(claim.directChild("read:what.some.stuff")).toBeNull();
});
it(".directChild('read:what.some.stuff.kid'): null", async () => {
expect(claim.directChild("read:what.some.stuff.kid")).toBeNull();
});
it(".directChild('admin:*'): null", async () => {
expect(claim.directChild("admin:*")).toBeNull();
});
it(".directChild('admin:something'): null", async () => {
expect(claim.directChild("admin:something")).toBeNull();
});
});
});
describe("Claim#isDirectChild()", () => {
describe('buildClaim("read:*")', () => {
const claim = buildClaim("read:*");
it(".isDirectChild('invalid:*'): error", async () => {
expect(() => claim.isDirectChild("invalid:*")).toThrowError();
});
it(".isDirectChild('read:*'): false", async () => {
expect(claim.isDirectChild("read:*")).toBeFalsy();
});
it(".isDirectChild('read:something.else'): false", async () => {
expect(claim.isDirectChild("read:something.else")).toBeFalsy();
});
it(".isDirectChild('admin:*'): false", async () => {
expect(claim.isDirectChild("admin:*")).toBeFalsy();
});
});
describe('buildClaim("read:something")', () => {
const claim = buildClaim("read:something");
it(".isDirectChild('read:*'): true", async () => {
expect(claim.isDirectChild("read:*")).toBeTruthy();
});
it(".isDirectChild('read:something'): false", async () => {
expect(claim.isDirectChild("read:something")).toBeFalsy();
});
it(".isDirectChild('read:something.else'): false", async () => {
expect(claim.isDirectChild("read:something.else")).toBeFalsy();
});
it(".isDirectChild('read:another.else'): false", async () => {
expect(claim.isDirectChild("read:another.else")).toBeFalsy();
});
it(".isDirectChild('admin:*'): false", async () => {
expect(claim.isDirectChild("admin:*")).toBeFalsy();
});
it(".isDirectChild('admin:something'): false", async () => {
expect(claim.isDirectChild("admin:something")).toBeFalsy();
});
});
describe('buildClaim("read:what.some.stuff")', () => {
const claim = buildClaim("read:what.some.stuff");
it(".isDirectChild('read:*'): false", async () => {
expect(claim.isDirectChild("read:*")).toBeFalsy();
});
it(".isDirectChild('read:what'): false", async () => {
expect(claim.isDirectChild("read:what")).toBeFalsy();
});
it(".isDirectChild('read:what.some'): true", async () => {
expect(claim.isDirectChild("read:what.some")).toBeTruthy();
});
it(".isDirectChild('read:what.some.stuff'): false", async () => {
expect(claim.isDirectChild("read:what.some.stuff")).toBeFalsy();
});
it(".isDirectChild('read:what.some.stuff.kid'): false", async () => {
expect(claim.isDirectChild("read:what.some.stuff.kid")).toBeFalsy();
});
it(".isDirectChild('admin:*'): false", async () => {
expect(claim.isDirectChild("admin:*")).toBeFalsy();
});
it(".isDirectChild('admin:something'): false", async () => {
expect(claim.isDirectChild("admin:something")).toBeFalsy();
});
});
});
describe("Claim#directDescendant()", () => {
describe('buildClaim("read:*")', () => {
const claim = buildClaim("read:*");
it(".directDescendant('invalid:*'): error", async () => {
expect(() => claim.directDescendant("invalid:*")).toThrowError();
});
it(".directDescendant('read:*'): null", async () => {
expect(claim.directDescendant("read:*")).toBeNull();
});
it(".directDescendant('read:something.else'): null", async () => {
expect(claim.directDescendant("read:something.else")).toBeNull();
});
it(".directDescendant('admin:*'): null", async () => {
expect(claim.directDescendant("admin:*")).toBeNull();
});
});
describe('buildClaim("read:something")', () => {
const claim = buildClaim("read:something");
it(".directDescendant('read:*'): 'something'", async () => {
expect(claim.directDescendant("read:*")).toEqual("something");
});
it(".directDescendant('read:something'): null", async () => {
expect(claim.directDescendant("read:something")).toBeNull();
});
it(".directDescendant('read:something.else'): null", async () => {
expect(claim.directDescendant("read:something.else")).toBeNull();
});
it(".directDescendant('admin:*'): null", async () => {
expect(claim.directDescendant("admin:*")).toBeNull();
});
it(".directDescendant('admin:something'): null", async () => {
expect(claim.directDescendant("admin:something")).toBeNull();
});
});
describe('buildClaim("read:what.some.stuff")', () => {
const claim = buildClaim("read:what.some.stuff");
it(".directDescendant('read:*'): 'what'", async () => {
expect(claim.directDescendant("read:*")).toEqual("what");
});
it(".directDescendant('read:what'): 'some'", async () => {
expect(claim.directDescendant("read:what")).toEqual("some");
});
it(".directDescendant('read:what.some'): 'stuff'", async () => {
expect(claim.directDescendant("read:what.some")).toEqual("stuff");
});
it(".directDescendant('read:something.else'): null", async () => {
expect(claim.directDescendant("read:something.else")).toBeNull();
});
it(".directDescendant('admin:*'): null", async () => {
expect(claim.directDescendant("admin:*")).toBeNull();
});
it(".directDescendant('admin:something'): null", async () => {
expect(claim.directDescendant("admin:something")).toBeNull();
});
});
});
describe("Claim#isDirectDescendant()", () => {
describe('buildClaim("read:*")', () => {
const claim = buildClaim("read:*");
it(".isDirectDescendant('invalid:*'): error", async () => {
expect(() => claim.isDirectDescendant("invalid:*")).toThrowError();
});
it(".isDirectDescendant('read:*'): false", async () => {
expect(claim.isDirectDescendant("read:*")).toBeFalsy();
});
it(".isDirectDescendant('read:something.else'): false", async () => {
expect(claim.isDirectDescendant("read:something.else")).toBeFalsy();
});
it(".isDirectDescendant('admin:*'): false", async () => {
expect(claim.isDirectDescendant("admin:*")).toBeFalsy();
});
});
describe('buildClaim("read:something")', () => {
const claim = buildClaim("read:something");
it(".isDirectDescendant('read:*'): true", async () => {
expect(claim.isDirectDescendant("read:*")).toBeTruthy();
});
it(".isDirectDescendant('read:something'): false", async () => {
expect(claim.isDirectDescendant("read:something")).toBeFalsy();
});
it(".isDirectDescendant('read:something.else'): false", async () => {
expect(claim.isDirectDescendant("read:something.else")).toBeFalsy();
});
it(".isDirectDescendant('admin:*'): false", async () => {
expect(claim.isDirectDescendant("admin:*")).toBeFalsy();
});
it(".isDirectDescendant('admin:something'): false", async () => {
expect(claim.isDirectDescendant("admin:something")).toBeFalsy();
});
});
describe('buildClaim("read:what.some.stuff")', () => {
const claim = buildClaim("read:what.some.stuff");
it(".isDirectDescendant('read:*'): true", async () => {
expect(claim.isDirectDescendant("read:*")).toBeTruthy();
});
it(".isDirectDescendant('read:what'): true", async () => {
expect(claim.isDirectDescendant("read:what")).toBeTruthy();
});
it(".isDirectDescendant('read:what.some'): true", async () => {
expect(claim.isDirectDescendant("read:what.some")).toBeTruthy();
});
it(".isDirectDescendant('read:something.else'): false", async () => {
expect(claim.isDirectDescendant("read:something.else")).toBeFalsy();
});
it(".isDirectDescendant('admin:*'): false", async () => {
expect(claim.isDirectDescendant("admin:*")).toBeFalsy();
});
it(".isDirectDescendant('admin:something'): false", async () => {
expect(claim.isDirectDescendant("admin:something")).toBeFalsy();
});
});
});
describe("extractVerbResource()", () => {
it('extractVerbResource("read:stuff")', () => {
expect(extractVerbResource("read:stuff")).toEqual({
verb: "read",
resource: "stuff",
});
});
it('extractVerbResource("read:*")', () => {
expect(extractVerbResource("read:*")).toEqual({
verb: "read",
resource: null,
});
});
it('extractVerbResource({ verb: "read", resource: "stuff" })', () => {
expect(extractVerbResource({ verb: "read", resource: "stuff" })).toEqual({
verb: "read",
resource: "stuff",
});
});
it('extractVerbResource({ verb: "read", resource: null })', () => {
expect(extractVerbResource({ verb: "read", resource: null })).toEqual({
verb: "read",
resource: null,
});
});
it("fails if given something else", () => {
expect(() => extractVerbResource({} as IClaimData)).toThrow(); // forcing it to provoke the error
});
});
describe("isValidClaimString(x)", () => {
it('isValidClaimString("read:stuff")', () => {
expect(isValidClaimString("read:stuff")).toBeTruthy();
});
it('isValidClaimString("read:stuff.nested")', () => {
expect(isValidClaimString("read:stuff.nested")).toBeTruthy();
});
it('isValidClaimString("read:stuff.nested.*")', () => {
expect(isValidClaimString("read:stuff.nested.*")).toBeTruthy();
});
it('isValidClaimString("read:*")', () => {
expect(isValidClaimString("read:*")).toBeTruthy();
});
it('isValidClaimString("bad:*")', () => {
expect(isValidClaimString("bad:*")).toBeFalsy();
});
it('isValidClaimString("bad!")', () => {
expect(isValidClaimString("bad!")).toBeFalsy();
});
it('isValidClaimString("read:stuff!")', () => {
expect(isValidClaimString("read:stuff!")).toBeFalsy();
});
it('isValidClaimString("read:stuff.*.other")', () => {
expect(isValidClaimString("read:stuff.*.other")).toBeFalsy();
});
it('isValidClaimString("read:stuff..other")', () => {
expect(isValidClaimString("read:stuff..other")).toBeFalsy();
});
it('isValidClaimString("read:stuff.other.")', () => {
expect(isValidClaimString("read:stuff.other.")).toBeFalsy();
});
});