Skip to content

Commit 065e538

Browse files
authored
Shared configs/workflows/loader (#152)
* use the loader in build * add Logos tests * update readme * fix lockfile * use release-package type config. * lint * update coverage * lint ignore
1 parent c61a98c commit 065e538

File tree

29 files changed

+2709
-639
lines changed

29 files changed

+2709
-639
lines changed

.github/workflows/deploy-apps.yml

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,17 @@ concurrency:
1414
group: 'pages'
1515
cancel-in-progress: true
1616

17+
env:
18+
CI: 1
19+
UPDATE: 1
20+
1721
jobs:
1822
deploy:
1923
environment:
2024
name: github-pages
2125
url: ${{ steps.deployment.outputs.page_url }}
2226
runs-on: ubuntu-latest
27+
2328
steps:
2429
- name: Checkout
2530
uses: actions/checkout@v4
@@ -39,25 +44,39 @@ jobs:
3944
fi
4045
if ! git diff --name-only $DIFF_RANGE | grep '^apps/' ; then
4146
echo "No changes in ./apps directory. Exiting early."
42-
echo "skip_steps=true" >> $GITHUB_OUTPUT
47+
echo "skip_steps=true" >> "$GITHUB_OUTPUT"
4348
else
44-
echo "skip_steps=false" >> $GITHUB_OUTPUT
49+
echo "skip_steps=false" >> "$GITHUB_OUTPUT"
4550
fi
4651
47-
- name: Set up Node
52+
- name: Set up Node (v24) with pnpm cache
4853
if: steps.changes.outputs.skip_steps != 'true'
4954
uses: actions/setup-node@v4
5055
with:
51-
node-version: lts/*
56+
node-version: '24'
57+
registry-url: 'https://registry.npmjs.org'
58+
cache: 'pnpm'
59+
cache-dependency-path: |
60+
pnpm-lock.yaml
61+
**/pnpm-lock.yaml
5262
53-
- name: Setup pnpm
63+
- name: Install pnpm
5464
if: steps.changes.outputs.skip_steps != 'true'
55-
uses: pnpm/[email protected]
65+
run: npm install -g pnpm
66+
67+
- name: Ensure pnpm store exists for caching
68+
if: steps.changes.outputs.skip_steps != 'true'
69+
shell: bash
70+
run: |
71+
STORE="$(pnpm store path)"
72+
echo "pnpm store path: $STORE"
73+
mkdir -p "$STORE"
5674
5775
- name: Install dependencies
5876
if: steps.changes.outputs.skip_steps != 'true'
59-
run: pnpm i
60-
- name: Build
77+
run: pnpm install --frozen-lockfile
78+
79+
- name: Build apps (with vite-node loader)
6180
if: steps.changes.outputs.skip_steps != 'true'
6281
env:
6382
NODE_OPTIONS: --import=${{ github.workspace }}/plugins/vite-node.plugin.loader.mjs

apps/nutritionfacts/coverage/coverage.yml

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
coverage:
22
totals:
3-
statements: 23.12%
4-
branches: 14.9%
5-
functions: 20.83%
6-
lines: 23.95%
7-
total: 20.7%
3+
statements: 0%
4+
branches: 0%
5+
functions: 0%
6+
lines: 0%
7+
total: 0%
88
src:
99
totals:
10-
statements: 45.63%
11-
branches: 44.17%
12-
functions: 43.75%
13-
lines: 45.63%
10+
statements: 0%
11+
branches: 15%
12+
functions: 6.25%
13+
lines: 0%
1414
"App.tsx":
1515
statements: 0%
1616
branches: 0%
@@ -69,30 +69,33 @@ coverage:
6969
lines: 0%
7070
uncovered_line_numbers: "4-19"
7171
"Main.tsx":
72-
statements: 87.5%
73-
branches: 83.33%
74-
functions: 100%
75-
lines: 87.5%
76-
uncovered_line_numbers: "26"
72+
statements: 0%
73+
branches: 0%
74+
functions: 0%
75+
lines: 0%
76+
uncovered_line_numbers: "6-26"
7777
assets:
7878
"Layout.ts":
79-
statements: 100%
79+
statements: 0%
8080
branches: 100%
81-
functions: 100%
82-
lines: 100%
81+
functions: 0%
82+
lines: 0%
83+
uncovered_line_numbers: "9-15"
8384
"Logos.tsx":
84-
statements: 100%
85-
branches: 100%
86-
functions: 100%
87-
lines: 100%
85+
statements: 0%
86+
branches: 0%
87+
functions: 0%
88+
lines: 0%
89+
uncovered_line_numbers: "23-244"
8890
"colors.ts":
89-
statements: 100%
91+
statements: 0%
9092
branches: 100%
9193
functions: 100%
92-
lines: 100%
94+
lines: 0%
95+
uncovered_line_numbers: "10"
9396
"consts.tsx":
94-
statements: 80%
95-
branches: 33.33%
97+
statements: 0%
98+
branches: 0%
9699
functions: 0%
97-
lines: 80%
98-
uncovered_line_numbers: "64"
100+
lines: 0%
101+
uncovered_line_numbers: "14-79"

apps/nutritionfacts/index.test.ts

Lines changed: 57 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,58 @@
1+
2+
import { beforeEach, describe, expect, it } from "vitest";
13
// @ts-expect-error Vite raw import
2-
import html from "./index.html?raw"
3-
import { describe, it, expect, beforeEach } from "vitest"
4-
5-
describe('index.html', () => {
6-
beforeEach(() => {
7-
document.documentElement.innerHTML = html
8-
document.documentElement.setAttribute('lang', 'en')
9-
})
10-
11-
it('should have correct doctype', () => {
12-
// jsdom does not expose doctype, so we skip this in jsdom
13-
expect(document.documentElement.lang).toBe('en')
14-
})
15-
16-
it('should have correct meta tags', () => {
17-
const charset = document.querySelector('meta[charset]')
18-
expect(charset).not.toBeNull()
19-
expect(charset?.getAttribute('charset')).toBe('UTF-8')
20-
21-
const viewport = document.querySelector('meta[name="viewport"]')
22-
expect(viewport).not.toBeNull()
23-
expect(viewport?.getAttribute('content')).toBe('width=device-width, initial-scale=1.0')
24-
25-
const version = document.querySelector('meta[name="application-version"]')
26-
expect(version).not.toBeNull()
27-
expect(version?.getAttribute('content')).toBe('%VITE_PACKAGE_VERSION%')
28-
29-
const name = document.querySelector('meta[name="application-name"]')
30-
expect(name).not.toBeNull()
31-
expect(name?.getAttribute('content')).toBe('%VITE_PACKAGE_NAME%')
32-
})
33-
34-
it('should have favicon link', () => {
35-
const favicon = document.querySelector('link[rel="icon"]')
36-
expect(favicon).not.toBeNull()
37-
expect(favicon?.getAttribute('type')).toBe('image/svg+xml')
38-
expect(favicon?.getAttribute('href')).toBe('/IgniteAI.svg')
39-
})
40-
41-
it('should have correct title', () => {
42-
expect(document.title).toBe('IgniteAI Nutrition Facts')
43-
})
44-
45-
it('should have root div', () => {
46-
const root = document.getElementById('root')
47-
expect(root).not.toBeNull()
48-
})
49-
50-
it('should load main script as module', () => {
51-
const script = document.querySelector('script[type="module"]')
52-
expect(script).not.toBeNull()
53-
expect(script?.getAttribute('src')).toBe('/src/Main.tsx')
54-
})
55-
})
4+
import html from "./index.html?raw";
5+
6+
describe("index.html", () => {
7+
beforeEach(() => {
8+
document.documentElement.innerHTML = html;
9+
document.documentElement.setAttribute("lang", "en");
10+
});
11+
12+
it("should have correct doctype", () => {
13+
// jsdom does not expose doctype, so we skip this in jsdom
14+
expect(document.documentElement.lang).toBe("en");
15+
});
16+
17+
it("should have correct meta tags", () => {
18+
const charset = document.querySelector("meta[charset]");
19+
expect(charset).not.toBeNull();
20+
expect(charset?.getAttribute("charset")).toBe("UTF-8");
21+
22+
const viewport = document.querySelector('meta[name="viewport"]');
23+
expect(viewport).not.toBeNull();
24+
expect(viewport?.getAttribute("content")).toBe(
25+
"width=device-width, initial-scale=1.0",
26+
);
27+
28+
const version = document.querySelector('meta[name="application-version"]');
29+
expect(version).not.toBeNull();
30+
expect(version?.getAttribute("content")).toBe("%VITE_PACKAGE_VERSION%");
31+
32+
const name = document.querySelector('meta[name="application-name"]');
33+
expect(name).not.toBeNull();
34+
expect(name?.getAttribute("content")).toBe("%VITE_PACKAGE_NAME%");
35+
});
36+
37+
it("should have favicon link", () => {
38+
const favicon = document.querySelector('link[rel="icon"]');
39+
expect(favicon).not.toBeNull();
40+
expect(favicon?.getAttribute("type")).toBe("image/svg+xml");
41+
expect(favicon?.getAttribute("href")).toBe("/IgniteAI.svg");
42+
});
43+
44+
it("should have correct title", () => {
45+
expect(document.title).toBe("IgniteAI Nutrition Facts");
46+
});
47+
48+
it("should have root div", () => {
49+
const root = document.getElementById("root");
50+
expect(root).not.toBeNull();
51+
});
52+
53+
it("should load main script as module", () => {
54+
const script = document.querySelector('script[type="module"]');
55+
expect(script).not.toBeNull();
56+
expect(script?.getAttribute("src")).toBe("/src/Main.tsx");
57+
});
58+
});

apps/nutritionfacts/package.json

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,32 @@
11
{
2-
"browserslist": [
3-
"extends @instructure/browserslist-config-instui"
4-
],
5-
"dependencies": {
6-
"@instructure.ai/aiinfo": "^1.6.0",
7-
"@instructure/ui": "^11.0.1",
8-
"react": "^19.2.0",
9-
"react-dom": "^19.2.0"
10-
},
11-
"devDependencies": {
12-
"@instructure.ai/shared-configs": "workspace:^"
13-
},
14-
"name": "@instructure.ai/nutritionfacts",
15-
"private": true,
16-
"repository": {
17-
"directory": "apps/nutritionfacts",
18-
"type": "git",
19-
"url": "https://github.com/instructure/instructure.ai"
20-
},
21-
"scripts": {
22-
"build": "vite build",
23-
"dev": "vite",
24-
"lint": "pnpm biome check",
25-
"preview": "vite preview",
26-
"test": "pnpm vitest run",
27-
"typecheck": "tsgo --noEmit",
28-
"update-cache": "vite-node ./scripts/updateCache.mts"
29-
},
30-
"type": "module",
31-
"version": "1.6.0"
2+
"browserslist": [
3+
"extends @instructure/browserslist-config-instui"
4+
],
5+
"dependencies": {
6+
"@instructure.ai/aiinfo": "workspace:^",
7+
"@instructure/ui": "^11.0.1",
8+
"react": "^19.2.0",
9+
"react-dom": "^19.2.0"
10+
},
11+
"devDependencies": {
12+
"@instructure.ai/shared-configs": "workspace:^"
13+
},
14+
"name": "@instructure.ai/nutritionfacts",
15+
"private": true,
16+
"repository": {
17+
"directory": "apps/nutritionfacts",
18+
"type": "git",
19+
"url": "https://github.com/instructure/instructure.ai"
20+
},
21+
"scripts": {
22+
"build": "vite build",
23+
"dev": "vite",
24+
"lint": "pnpm biome check",
25+
"preview": "vite preview",
26+
"test": "pnpm vitest run",
27+
"typecheck": "tsgo --noEmit",
28+
"update-cache": "vite-node ./scripts/updateCache.mts"
29+
},
30+
"type": "module",
31+
"version": "1.6.0"
3232
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { beforeEach, describe, expect, it, vi } from "vitest";
2+
3+
// Set up the mock before importing Divider
4+
vi.mock("@instructure/ui", () => {
5+
const ViewMock = vi.fn(({ children, ...props }) => (
6+
<div data-testid="view-mock" {...props}>
7+
{children}
8+
</div>
9+
));
10+
return { View: ViewMock };
11+
});
12+
13+
import { Divider } from "./Divider";
14+
15+
describe("Divider", () => {
16+
let ViewMock: ReturnType<typeof vi.fn>;
17+
18+
beforeEach(async () => {
19+
// Dynamically import the mock after vi.mock is set up
20+
const mocked =
21+
await vi.importMock<typeof import("@instructure/ui")>("@instructure/ui");
22+
ViewMock = mocked.View as unknown as ReturnType<typeof vi.fn>;
23+
ViewMock.mockClear();
24+
});
25+
26+
it("renders a View with correct props", async () => {
27+
const { container, getByTestId } = require("@testing-library/react").render(
28+
<Divider />,
29+
);
30+
expect(ViewMock).toHaveBeenCalledTimes(1);
31+
const call = ViewMock.mock.calls[0][0];
32+
expect(call.as).toBe("div");
33+
expect(call.borderColor).toBe("primary");
34+
expect(call.borderWidth).toBe("medium 0 0");
35+
expect(call.margin).toBe("0 0 medium");
36+
expect(getByTestId("view-mock")).toBeTruthy();
37+
expect(
38+
container.querySelector("div[data-testid='view-mock']"),
39+
).not.toBeNull();
40+
});
41+
42+
it("does not render children", async () => {
43+
require("@testing-library/react").render(<Divider />);
44+
const call = ViewMock.mock.calls[0][0];
45+
expect(call.children).toBeUndefined();
46+
});
47+
});

0 commit comments

Comments
 (0)