@inrupt/solid-client
Version:
Make your web apps work with Solid Pods.
287 lines (251 loc) • 9.28 kB
text/typescript
// Copyright Inrupt Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
import { describe, it, expect } from "@jest/globals";
import { buildThing } from "./build";
import * as adders from "./add";
import * as setters from "./set";
import * as removers from "./remove";
import { asIri, createThing, isThing } from "./thing";
import type { ThingLocal } from "../interfaces";
import { getInteger, getStringWithLocale } from "./get";
describe("Thing Builder API", () => {
it("adds the same properties as non-fluent functions", () => {
const startingThing = createThing();
const builtThing = buildThing(startingThing)
.addInteger("https://some.vocab/predicate", 42)
.addStringEnglish("https://some.vocab/predicate", "Some English string")
.addStringWithLocale(
"https://some.vocab/predicate",
"Some string",
"nl-nl",
)
.build();
let nonBuilderThing = adders.addInteger(
startingThing,
"https://some.vocab/predicate",
42,
);
nonBuilderThing = adders.addStringEnglish(
nonBuilderThing,
"https://some.vocab/predicate",
"Some English string",
);
nonBuilderThing = adders.addStringWithLocale(
nonBuilderThing,
"https://some.vocab/predicate",
"Some string",
"nl-nl",
);
expect(builtThing).toStrictEqual(nonBuilderThing);
});
it("replaces the same properties as the non-fluent functions", () => {
let startingThing = adders.addDecimal(
createThing(),
"https://some.vocab/predicate",
4.2,
);
startingThing = adders.addStringWithLocale(
startingThing,
"https://some-other.vocab/predicate",
"Some string",
"nl-nl",
);
const builtThing = buildThing(startingThing)
.setDecimal("https://some.vocab/predicate", 13.37)
.setStringEnglish(
"https://some-other.vocab/predicate",
"Some English string",
)
.setStringWithLocale(
"https://some-other.vocab/predicate",
"Some other string",
"nl-nl",
)
.build();
let nonBuilderThing = setters.setDecimal(
startingThing,
"https://some.vocab/predicate",
13.37,
);
nonBuilderThing = setters.setStringEnglish(
nonBuilderThing,
"https://some-other.vocab/predicate",
"Some English string",
);
nonBuilderThing = setters.setStringWithLocale(
nonBuilderThing,
"https://some-other.vocab/predicate",
"Some other string",
"nl-nl",
);
expect(builtThing).toStrictEqual(nonBuilderThing);
});
it("removes the same properties as the non-fluent functions", () => {
let startingThing = adders.addDecimal(
createThing(),
"https://some.vocab/predicate",
4.2,
);
startingThing = adders.addStringEnglish(
startingThing,
"https://some.vocab/predicate-english",
"Some English string",
);
startingThing = adders.addStringWithLocale(
startingThing,
"https://some.vocab/predicate",
"Some string",
"en-gb",
);
startingThing = adders.addBoolean(
startingThing,
"https://some-other.vocab/predicate",
true,
);
startingThing = adders.addStringNoLocale(
startingThing,
"https://yet-another.vocab/predicate",
"Some unlocalised string",
);
const builtThing = buildThing(startingThing)
.removeStringEnglish(
"https://some.vocab/predicate-english",
"Some English string",
)
.removeStringWithLocale(
"https://some.vocab/predicate",
"Some string",
"en-gb",
)
.removeBoolean("https://some-other.vocab/predicate", true)
.removeAll("https://yet-another.vocab/predicate")
.build();
let nonBuilderThing = removers.removeStringEnglish(
startingThing,
"https://some.vocab/predicate-english",
"Some English string",
);
nonBuilderThing = removers.removeStringWithLocale(
nonBuilderThing,
"https://some.vocab/predicate",
"Some string",
"en-gb",
);
nonBuilderThing = removers.removeBoolean(
nonBuilderThing,
"https://some-other.vocab/predicate",
true,
);
nonBuilderThing = removers.removeAll(
nonBuilderThing,
"https://yet-another.vocab/predicate",
);
expect(builtThing).toStrictEqual(nonBuilderThing);
});
it("initialises a new Thing if not passed one", () => {
const thing = buildThing().build();
expect(isThing(thing)).toBe(true);
});
it("can take options for the Thing initialisation", () => {
const thing = buildThing({
url: "https://some.pod/resource#thing",
}).build();
expect(asIri(thing)).toBe("https://some.pod/resource#thing");
});
it("preserves the type (ThingLocal or ThingPersisted) of Things passed to it", () => {
// We're only going to check for expected TypeScript errors:
expect.assertions(0);
/* eslint-disable @typescript-eslint/no-unused-vars */
// @ts-expect-error Since we're passing the `url` option, `buildThing`
// should return a ThingPersisted, which should cause an error when
// assigning to a ThingLocal variable:
const _thingPersistedDirect: ThingLocal = buildThing({
url: "https://some.pod/resource#thing",
}).build();
// @ts-expect-error Since we're passing a ThingPersisted as the starting
// Thing, `buildThing` should also return a ThingPersisted, which should
// cause an error when assigning to a ThingLocal variable:
const _thingPersisted: ThingLocal = buildThing(
createThing({ url: "https://some.pod/resource#thing" }),
).build();
// Since we're passing the `name` option, `buildThing` should return a ThingLocal,
// which should not cause an error when assigning to a ThingLocal variable:
const _thingLocalDirect: ThingLocal = buildThing({ name: "thing" }).build();
// Since we're passing a ThingLocal as the starting Thing,
// `buildThing` should also return a ThingLocal,
// which should not cause an error when assigning to a ThingLocal variable:
const _thingLocal: ThingLocal = buildThing(
createThing({ name: "thing" }),
).build();
/* eslint-enable @typescript-eslint/no-unused-vars */
});
it("has equivalents for every adder", () => {
const adderNames = Object.keys(adders).filter(
(adderName) => adderName.substring(0, 3) === "add",
);
expect.assertions(adderNames.length * 2);
const builder = buildThing();
adderNames.forEach((adderName) => {
expect((builder as Record<string, unknown>)[adderName]).toBeDefined();
expect(typeof (builder as Record<string, unknown>)[adderName]).toBe(
"function",
);
});
});
it("has equivalents for every setter", () => {
const setterNames = Object.keys(setters).filter(
(setterName) => setterName.substring(0, 3) === "set",
);
expect.assertions(setterNames.length * 2);
const builder = buildThing();
setterNames.forEach((setterName) => {
expect((builder as Record<string, unknown>)[setterName]).toBeDefined();
expect(typeof (builder as Record<string, unknown>)[setterName]).toBe(
"function",
);
});
});
it("has equivalents for every remover", () => {
const removerNames = Object.keys(removers).filter(
(removerName) => removerName.substring(0, 6) === "remove",
);
expect.assertions(removerNames.length * 2);
const builder = buildThing();
removerNames.forEach((removerName) => {
expect((builder as Record<string, unknown>)[removerName]).toBeDefined();
expect(typeof (builder as Record<string, unknown>)[removerName]).toBe(
"function",
);
});
});
it("has methods that need not be chained", () => {
const builder = buildThing().addInteger("https://some.vocab/predicate", 42);
builder.addStringWithLocale(
"https://some.vocab/predicate",
"Some string",
"nl-nl",
);
const thing = builder.build();
expect(getInteger(thing, "https://some.vocab/predicate")).toBe(42);
expect(
getStringWithLocale(thing, "https://some.vocab/predicate", "nl-nl"),
).toBe("Some string");
});
});