Chore: Upgrade to AIK
& Massive Overhaul to internal processing #78
14
package.json
14
package.json
|
@ -12,14 +12,14 @@
|
|||
"lint:fix": "biome check --apply .",
|
||||
"ci:version": "pnpm changeset version",
|
||||
"ci:publish": "pnpm changeset publish",
|
||||
"ci:test:api": "pnpm --filter astro-ghostcms test:ci",
|
||||
"test:api": "pnpm --filter astro-ghostcms test",
|
||||
"test:api:watch": "pnpm --filter astro-ghostcms test:watch",
|
||||
"test:api:coverage": "pnpm --filter astro-ghostcms test:coverage",
|
||||
"ci:test:integration": "pnpm --filter astro-ghostcms test:ci",
|
||||
"test:integration": "pnpm --filter astro-ghostcms test",
|
||||
"test:integration:watch": "pnpm --filter astro-ghostcms test:watch",
|
||||
"test:integration:coverage": "pnpm --filter astro-ghostcms test:coverage",
|
||||
"test:create": "pnpm --filter create-astro-ghostcms test",
|
||||
"test:slg": "pnpm --filter starlight-ghostcms test",
|
||||
"test:slg:watch": "pnpm --filter starlight-ghostcms test:watch",
|
||||
"test:slg:coverage": "pnpm --filter starlight-ghostcms test:coverage"
|
||||
"test:starlight": "pnpm --filter starlight-ghostcms test",
|
||||
"test:starlight:watch": "pnpm --filter starlight-ghostcms test:watch",
|
||||
"test:starlight:coverage": "pnpm --filter starlight-ghostcms test:coverage"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "1.5.3",
|
||||
|
|
|
@ -49,11 +49,17 @@
|
|||
"./open-graph/*": "./src/integrations/satoriog/routes/*"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest",
|
||||
"test:coverage": "vitest run --coverage",
|
||||
"test:ci": "vitest run --coverage.enabled --coverage.reporter='text-summary'"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"astro": "^4.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vitest": "^1.3.0",
|
||||
"vitest-fetch-mock": "^0.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/rss": "^4.0.5",
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
import { assert, beforeEach, describe, expect, test } from "vitest";
|
||||
|
||||
import { TSGhostContentAPI } from "@ts-ghost/content-api";
|
||||
|
||||
describe("content-api", () => {
|
||||
let api: TSGhostContentAPI;
|
||||
beforeEach(() => {
|
||||
api = new TSGhostContentAPI("https://ghost.org", "59d4bf56c73c04a18c867dc3ba", "v5.0");
|
||||
});
|
||||
|
||||
test("content-api", () => {
|
||||
expect(api).toBeDefined();
|
||||
});
|
||||
|
||||
test("content-api shouldn't instantiate with an incorrect url", () => {
|
||||
assert.throws(() => {
|
||||
const api = new TSGhostContentAPI("ghost.org", "59d4bf56c73c04a18c867dc3ba", "v5.0");
|
||||
api.settings;
|
||||
});
|
||||
});
|
||||
|
||||
test("content-api shouldn't instantiate with an incorrect key", () => {
|
||||
assert.throws(() => {
|
||||
const api = new TSGhostContentAPI("https://ghost.org", "a", "v5.0");
|
||||
api.settings;
|
||||
});
|
||||
});
|
||||
|
||||
test("content-api shouldn't instantiate with an incorrect version", () => {
|
||||
assert.throws(() => {
|
||||
const api = new TSGhostContentAPI(
|
||||
"https://ghost.org",
|
||||
"1efedd9db174adee2d23d982:4b74dca0219bad629852191af326a45037346c2231240e0f7aec1f9371cc14e8",
|
||||
// @ts-expect-error
|
||||
"v4.0",
|
||||
);
|
||||
api.settings;
|
||||
});
|
||||
});
|
||||
|
||||
test("content-api.posts", () => {
|
||||
expect(api.posts).toBeDefined();
|
||||
expect(api.posts.browse).toBeDefined();
|
||||
|
||||
expect(api.posts.read).toBeDefined();
|
||||
});
|
||||
|
||||
test("content-api.pages", () => {
|
||||
expect(api.pages).toBeDefined();
|
||||
expect(api.pages.browse).toBeDefined();
|
||||
expect(api.pages.read).toBeDefined();
|
||||
});
|
||||
|
||||
test("content-api.tags", () => {
|
||||
expect(api.tags).toBeDefined();
|
||||
expect(api.tags.browse).toBeDefined();
|
||||
expect(api.tags.read).toBeDefined();
|
||||
});
|
||||
|
||||
test("content-api.tiers", () => {
|
||||
expect(api.tiers).toBeDefined();
|
||||
expect(api.tiers.browse).toBeDefined();
|
||||
expect(api.tiers.read).toBeDefined();
|
||||
});
|
||||
|
||||
test("content-api.authors", () => {
|
||||
expect(api.authors).toBeDefined();
|
||||
expect(api.authors.browse).toBeDefined();
|
||||
expect(api.authors.read).toBeDefined();
|
||||
// @ts-expect-error
|
||||
expect(api.authors.add).toBeUndefined();
|
||||
// @ts-expect-error
|
||||
expect(api.authors.edit).toBeUndefined();
|
||||
expect(api.authors).toBeDefined();
|
||||
});
|
||||
|
||||
test("content-api.settings", () => {
|
||||
expect(api.settings).toBeDefined();
|
||||
expect(api.settings.fetch).toBeDefined();
|
||||
// @ts-expect-error
|
||||
expect(api.settings.read).toBeUndefined();
|
||||
// @ts-expect-error
|
||||
expect(api.settings.browse).toBeUndefined();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,32 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
|
||||
// Modified version of invariant script to allow tests
|
||||
const isProduction = false;
|
||||
const prefix: string = "Invariant failed";
|
||||
function invariant(condition: any, message?: string | (() => string)) {
|
||||
if (condition) {
|
||||
return;
|
||||
}
|
||||
if (isProduction) {
|
||||
throw new Error(prefix);
|
||||
}
|
||||
const provided: string | undefined =
|
||||
typeof message === "function" ? message() : message;
|
||||
const value: string = provided ? `${prefix}: ${provided}` : prefix;
|
||||
return value;
|
||||
}
|
||||
|
||||
// TEST SECTION
|
||||
const testTrue = true;
|
||||
const testFalse = false;
|
||||
describe("test invariant", () => {
|
||||
it("Test `true` value", () => {
|
||||
invariant(testTrue, "This should not error");
|
||||
expect(null);
|
||||
});
|
||||
|
||||
it("Test `false` value", () => {
|
||||
invariant(testFalse, "This should Error");
|
||||
expect(String("Invariant failed"));
|
||||
});
|
||||
});
|
|
@ -0,0 +1,146 @@
|
|||
import createFetchMock from "vitest-fetch-mock";
|
||||
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
||||
|
||||
import { TSGhostContentAPI } from "@ts-ghost/content-api";
|
||||
|
||||
const fetchMocker = createFetchMock(vi);
|
||||
|
||||
describe("authors api .browse() Args Type-safety", () => {
|
||||
const url = process.env.VITE_GHOST_URL || "https://my-ghost-blog.com";
|
||||
const key = process.env.VITE_GHOST_CONTENT_API_KEY || "59d4bf56c73c04a18c867dc3ba";
|
||||
const api = new TSGhostContentAPI(url, key, "v5.0");
|
||||
test(".browse() params shouldnt accept invalid params", () => {
|
||||
// @ts-expect-error - shouldnt accept invalid params
|
||||
const browse = api.authors.browse({ pp: 2 });
|
||||
expect(browse.getParams().browseParams).toStrictEqual({});
|
||||
});
|
||||
|
||||
test(".browse() 'order' params should ony accept fields values", () => {
|
||||
// @ts-expect-error - order should ony contain field
|
||||
expect(() => api.authors.browse({ order: "foo ASC" })).toThrow();
|
||||
// valid
|
||||
expect(api.authors.browse({ order: "name ASC" }).getParams().browseParams).toStrictEqual({
|
||||
order: "name ASC",
|
||||
});
|
||||
expect(api.authors.browse({ order: "name ASC,slug DESC" }).getParams().browseParams).toStrictEqual({
|
||||
order: "name ASC,slug DESC",
|
||||
});
|
||||
expect(
|
||||
api.authors.browse({ order: "name ASC,slug DESC,location ASC" }).getParams().browseParams
|
||||
).toStrictEqual({
|
||||
order: "name ASC,slug DESC,location ASC",
|
||||
});
|
||||
// @ts-expect-error - order should ony contain field (There is a typo in location)
|
||||
expect(() => api.authors.browse({ order: "name ASC,slug DESC,locaton ASC" })).toThrow();
|
||||
});
|
||||
|
||||
test(".browse() 'filter' params should ony accept valid field", () => {
|
||||
expect(() =>
|
||||
api.authors.browse({
|
||||
// @ts-expect-error - order should ony contain field
|
||||
filter: "foo:bar",
|
||||
})
|
||||
).toThrow();
|
||||
expect(
|
||||
api.authors
|
||||
.browse({
|
||||
filter: "name:bar",
|
||||
})
|
||||
.getParams().browseParams
|
||||
).toStrictEqual({
|
||||
filter: "name:bar",
|
||||
});
|
||||
expect(
|
||||
api.authors
|
||||
.browse({
|
||||
filter: "name:bar+slug:-test",
|
||||
})
|
||||
.getParams().browseParams
|
||||
).toStrictEqual({
|
||||
filter: "name:bar+slug:-test",
|
||||
});
|
||||
});
|
||||
|
||||
test(".browse 'fields' argument should ony accept valid fields", () => {
|
||||
expect(
|
||||
api.authors
|
||||
.browse()
|
||||
.fields({
|
||||
// @ts-expect-error - order should ony contain field
|
||||
foo: true,
|
||||
})
|
||||
.getOutputFields()
|
||||
).toEqual([]);
|
||||
|
||||
expect(api.authors.browse().fields({ location: true }).getOutputFields()).toEqual(["location"]);
|
||||
expect(api.authors.browse().fields({ name: true, website: true }).getOutputFields()).toEqual([
|
||||
"name",
|
||||
"website",
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("authors resource mocked", () => {
|
||||
let api: TSGhostContentAPI;
|
||||
|
||||
beforeEach(() => {
|
||||
api = new TSGhostContentAPI("https://my-ghost-blog.com", "59d4bf56c73c04a18c867dc3ba", "v5.0");
|
||||
fetchMocker.enableMocks();
|
||||
});
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
test("aouthors should be fetched correctly", async () => {
|
||||
const authors = api.authors;
|
||||
expect(authors).not.toBeUndefined();
|
||||
const browseQuery = authors
|
||||
.browse({
|
||||
page: 2,
|
||||
})
|
||||
.fields({
|
||||
name: true,
|
||||
id: true,
|
||||
});
|
||||
expect(browseQuery).not.toBeUndefined();
|
||||
expect(browseQuery.getOutputFields()).toStrictEqual(["name", "id"]);
|
||||
|
||||
fetchMocker.doMockOnce(
|
||||
JSON.stringify({
|
||||
authors: [
|
||||
{
|
||||
name: "foo",
|
||||
id: "eaoizdjoa1321123",
|
||||
},
|
||||
],
|
||||
meta: {
|
||||
pagination: {
|
||||
page: 1,
|
||||
limit: 15,
|
||||
pages: 1,
|
||||
total: 1,
|
||||
next: null,
|
||||
prev: null,
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
const result = await browseQuery.fetch();
|
||||
expect(fetchMocker).toHaveBeenCalledTimes(1);
|
||||
expect(fetchMocker).toHaveBeenCalledWith(
|
||||
"https://my-ghost-blog.com/ghost/api/content/authors/?page=2&fields=name%2Cid&key=59d4bf56c73c04a18c867dc3ba",
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Accept-Version": "v5.0",
|
||||
},
|
||||
}
|
||||
);
|
||||
expect(result).not.toBeUndefined();
|
||||
if (result.success) {
|
||||
expect(result.data.length).toBe(1);
|
||||
expect(result.data[0].name).toBe("foo");
|
||||
expect(result.data[0].id).toBe("eaoizdjoa1321123");
|
||||
}
|
||||
});
|
||||
});
|
|
@ -0,0 +1,55 @@
|
|||
import { describe, expect, test } from "vitest";
|
||||
|
||||
import { TSGhostContentAPI } from "@ts-ghost/content-api";
|
||||
import type { Post } from "./index";
|
||||
|
||||
const url = process.env.VITE_GHOST_URL || "https://my-ghost-blog.com";
|
||||
const key = process.env.VITE_GHOST_CONTENT_API_KEY || "59d4bf56c73c04a18c867dc3ba";
|
||||
|
||||
describe("posts api .browse() Args Type-safety", () => {
|
||||
const api = new TSGhostContentAPI(url, key, "v5.0");
|
||||
test(".browse() params shouldnt accept invalid params", () => {
|
||||
// @ts-expect-error - shouldnt accept invalid params
|
||||
const browse = api.posts.browse({ pp: 2 });
|
||||
expect(browse.getParams().browseParams).toStrictEqual({});
|
||||
|
||||
const outputFields = {
|
||||
slug: true,
|
||||
title: true,
|
||||
// @ts-expect-error - shouldnt accept invalid params
|
||||
foo: true,
|
||||
} satisfies { [k in keyof Post]?: true | undefined };
|
||||
|
||||
const test = api.posts
|
||||
.browse()
|
||||
// @ts-expect-error - shouldnt accept invalid params
|
||||
.fields(outputFields);
|
||||
expect(test.getOutputFields()).toEqual(["slug", "title"]);
|
||||
|
||||
const fields = ["slug", "title", "foo"] as const;
|
||||
const unknownOriginFields = fields.reduce((acc, k) => {
|
||||
acc[k as keyof Post] = true;
|
||||
return acc;
|
||||
}, {} as { [k in keyof Post]?: true | undefined });
|
||||
const result = api.posts.browse().fields(unknownOriginFields);
|
||||
expect(result.getOutputFields()).toEqual(["slug", "title"]);
|
||||
});
|
||||
test(".browse() params, output fields declare const", () => {
|
||||
const outputFields = {
|
||||
slug: true,
|
||||
title: true,
|
||||
} satisfies { [k in keyof Post]?: true | undefined };
|
||||
|
||||
const test = api.posts.browse().fields(outputFields);
|
||||
expect(test.getOutputFields()).toEqual(["slug", "title"]);
|
||||
|
||||
// @ts-expect-error - shouldnt accept invalid params
|
||||
expect(() => api.posts.browse({ filter: "slugg:test" })).toThrow();
|
||||
// @ts-expect-error - shouldnt accept invalid params
|
||||
expect(() => api.posts.browse({ filter: "slug:test,foo:-[bar,baz]" })).toThrow();
|
||||
expect(api.posts.browse({ filter: "slug:test,tags:-[bar,baz]" })).toBeDefined();
|
||||
expect(api.posts.browse({ filter: "slug:test,tags:[bar,baz]" })).toBeDefined();
|
||||
// @ts-expect-error - shouldnt accept invalid params
|
||||
expect(() => api.posts.browse({ filter: "slug:test,food:-[bar,baz]" })).toThrow();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,36 @@
|
|||
import { beforeEach, describe, expect, test } from "vitest";
|
||||
|
||||
import { TSGhostContentAPI } from "@ts-ghost/content-api";
|
||||
|
||||
const url = process.env.VITE_GHOST_URL || "https://my-ghost-blog.com";
|
||||
const key = process.env.VITE_GHOST_CONTENT_API_KEY || "59d4bf56c73c04a18c867dc3ba";
|
||||
|
||||
describe("settings integration tests browse", () => {
|
||||
let api: TSGhostContentAPI;
|
||||
beforeEach(() => {
|
||||
api = new TSGhostContentAPI(url, key, "v5.0");
|
||||
});
|
||||
test("settings.fetch()", async () => {
|
||||
const result = await api.settings.fetch();
|
||||
expect(result).not.toBeUndefined();
|
||||
expect(result).not.toBeNull();
|
||||
if (!result.success) {
|
||||
expect(result.errors).toBeDefined();
|
||||
expect(result.errors).toHaveLength(1);
|
||||
} else {
|
||||
expect(result.data).toBeDefined();
|
||||
const settings = result.data;
|
||||
![]() You can also use You can also use `expect({}).toEqual({])` to deep check object equality
![]() The API Schemas are actually copied from the The API Schemas are actually copied from the `ts-ghost` ones for local dev typing I just copied his tests over for sanity purposes... they succeed... thats about all i know about those ones
|
||||
expect(settings).toBeDefined();
|
||||
expect(settings.title).toBe("Astro Starter");
|
||||
expect(settings.description).toBe("Thoughts, stories and ideas.");
|
||||
expect(settings.logo).toBeNull();
|
||||
expect(settings.cover_image).toBe("https://static.ghost.org/v4.0.0/images/publication-cover.jpg");
|
||||
expect(settings.icon).toBeNull();
|
||||
expect(settings.lang).toBe("en");
|
||||
expect(settings.timezone).toBe("Etc/UTC");
|
||||
expect(settings.codeinjection_head).toBeNull();
|
||||
expect(settings.codeinjection_foot).toBeNull();
|
||||
expect(settings.members_support_address).toBe("noreply");
|
||||
}
|
||||
});
|
||||
});
|
|
@ -0,0 +1,54 @@
|
|||
import { expect, describe, it } from "vitest";
|
||||
import { GhostUserConfigSchema } from "./userconfig";
|
||||
|
||||
describe("GhostUserConfigSchema", () => {
|
||||
it("should validate a valid user config", () => {
|
||||
const validConfig = {
|
||||
ghostURL: "https://ghostdemo.matthiesen.xyz",
|
||||
disableThemeProvider: true,
|
||||
ThemeProvider: {
|
||||
theme: "@matthiesenxyz/astro-ghostcms-theme-default",
|
||||
},
|
||||
disableDefault404: false,
|
||||
enableRSSFeed: true,
|
||||
enableOGImages: true,
|
||||
sitemap: {
|
||||
// sitemap configuration
|
||||
},
|
||||
robotstxt: {
|
||||
// robotstxt configuration
|
||||
},
|
||||
fullConsoleLogs: false,
|
||||
};
|
||||
|
||||
const result = GhostUserConfigSchema.safeParse(validConfig);
|
||||
|
||||
expect(result.success).to.be.true;
|
||||
expect(result.data).to.deep.equal(validConfig);
|
||||
});
|
||||
|
||||
it("should invalidate an invalid user config", () => {
|
||||
const invalidConfig = {
|
||||
ghostURL: "invalid-url",
|
||||
disableThemeProvider: "true",
|
||||
ThemeProvider: {
|
||||
theme: 123,
|
||||
},
|
||||
disableDefault404: "false",
|
||||
enableRSSFeed: "true",
|
||||
enableOGImages: "true",
|
||||
sitemap: {
|
||||
// invalid sitemap configuration
|
||||
},
|
||||
robotstxt: {
|
||||
// invalid robotstxt configuration
|
||||
},
|
||||
fullConsoleLogs: "false",
|
||||
};
|
||||
|
||||
const result = GhostUserConfigSchema.safeParse(invalidConfig);
|
||||
|
||||
expect(result.success).to.be.false;
|
||||
expect(!result.success).to.exist;
|
||||
});
|
||||
});
|
|
@ -0,0 +1,12 @@
|
|||
/// <reference types="vitest" />
|
||||
/// <reference types="vite/client" />
|
||||
import { defineProject } from 'vitest/config'
|
||||
|
||||
export default defineProject({
|
||||
test: {
|
||||
globals: true,
|
||||
include: ["./**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
|
||||
watchExclude: [".*\\/node_modules\\/.*", ".*\\/build\\/.*"],
|
||||
exclude: ["node_modules", "dist", ".idea", ".git", ".cache"],
|
||||
},
|
||||
})
|
|
@ -65,6 +65,13 @@ importers:
|
|||
vite:
|
||||
specifier: ^5.1.4
|
||||
version: 5.1.4(@types/node@20.11.19)
|
||||
devDependencies:
|
||||
vitest:
|
||||
specifier: ^1.3.0
|
||||
version: 1.3.0(@types/node@20.11.19)(@vitest/ui@1.3.0)
|
||||
vitest-fetch-mock:
|
||||
specifier: ^0.2.2
|
||||
version: 0.2.2(vitest@1.3.0)
|
||||
|
||||
packages/astro-ghostcms-brutalbyelian:
|
||||
dependencies:
|
||||
|
@ -8809,7 +8816,7 @@ packages:
|
|||
strip-literal: 2.0.0
|
||||
tinybench: 2.6.0
|
||||
tinypool: 0.8.2
|
||||
vite: 5.1.3(@types/node@20.11.19)
|
||||
vite: 5.1.4(@types/node@20.11.19)
|
||||
vite-node: 1.3.0(@types/node@20.11.19)
|
||||
why-is-node-running: 2.2.2
|
||||
transitivePeerDependencies:
|
||||
|
|
Loading…
Reference in New Issue
Are these live keys?? Might not want to commit these!
These are Ghosts public demo keys that ghost provides for testing purposes