Skip to content

Commit b4e8173

Browse files
authored
Merge pull request #8 from wuespace/testing
Automated testing
2 parents 6aec27a + b28c36b commit b4e8173

File tree

9 files changed

+216
-48
lines changed

9 files changed

+216
-48
lines changed

.github/workflows/deno.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# This workflow uses actions that are not certified by GitHub.
2+
# They are provided by a third-party and are governed by
3+
# separate terms of service, privacy policy, and support
4+
# documentation.
5+
6+
# This workflow will install Deno then run `deno lint` and `deno test`.
7+
# For more information see: https://github.com/denoland/setup-deno
8+
9+
name: Deno
10+
11+
on:
12+
push:
13+
branches: ["main"]
14+
pull_request:
15+
branches: ["main"]
16+
17+
permissions:
18+
contents: read
19+
20+
jobs:
21+
test:
22+
runs-on: ubuntu-latest
23+
24+
steps:
25+
- name: Setup repo
26+
uses: actions/checkout@v4
27+
28+
- name: Setup Deno
29+
uses: denoland/setup-deno@61fe2df320078202e33d7d5ad347e7dcfa0e8f31 # v1.1.2
30+
with:
31+
deno-version: v2.x
32+
33+
- name: Verify formatting
34+
run: deno fmt --check
35+
36+
- name: Run linter
37+
run: deno lint
38+
39+
- name: Run tests
40+
run: deno task test

.pre-commit-config.yaml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,12 @@ repos:
3434
# pass_filenames: false
3535
description: "Type-check code using Deno's built-in type checker"
3636
stages: [pre-commit]
37-
# - id: deno-test
38-
# name: deno-test
39-
# entry: deno task test
40-
# language: system
41-
# files: \.(ts|tsx|js|jsx)$
42-
# pass_filenames: false
43-
# always_run: true
44-
# description: "Run tests using Deno's built-in test runner"
45-
# stages: [pre-commit]
37+
- id: deno-test
38+
name: deno-test
39+
entry: deno task test
40+
language: system
41+
files: \.(ts|tsx|js|jsx)$
42+
pass_filenames: false
43+
always_run: true
44+
description: "Run tests using Deno's built-in test runner"
45+
stages: [pre-commit]

deno.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55
"tasks": {
66
"dev": "deno run -A --watch example/main.tsx",
77
"cli": "deno run -A --watch cli.ts",
8-
"update:i18n": "deno run -A example/i18n.ts"
8+
"update:i18n": "deno run -A example/i18n.ts",
9+
"test": "deno test -A"
910
},
1011
"exports": "./lib/mod.ts",
1112
"imports": {
1213
"@hono/hono": "jsr:@hono/hono@4",
1314
"@std/assert": "jsr:@std/assert@1",
15+
"@std/expect": "jsr:@std/expect@^1.0.17",
1416
"@std/fs": "jsr:@std/fs@^1.0.20",
1517
"typescript": "npm:typescript@^5.9.3",
1618
"@wuespace/honolate": "./lib/mod.ts"

deno.lock

Lines changed: 14 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

example/locales/babeledit-project.babel

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
<name>main</name>
2121
<children>
2222
<concept_node>
23-
<name>ABC {0} DEF</name>
23+
<name>Hello world!</name>
2424
<description/>
2525
<comment/>
2626
<translations>
@@ -35,7 +35,22 @@
3535
</translations>
3636
</concept_node>
3737
<concept_node>
38-
<name>Hello world!</name>
38+
<name>Lazy term</name>
39+
<description/>
40+
<comment/>
41+
<translations>
42+
<translation>
43+
<language>de-DE</language>
44+
<approved>false</approved>
45+
</translation>
46+
<translation>
47+
<language>en-US</language>
48+
<approved>false</approved>
49+
</translation>
50+
</translations>
51+
</concept_node>
52+
<concept_node>
53+
<name>This text contains {0} \{} curly braces and \\{\{}}\{0}.</name>
3954
<description/>
4055
<comment/>
4156
<translations>
@@ -50,17 +65,17 @@
5065
</translations>
5166
</concept_node>
5267
<concept_node>
53-
<name>Welcome to the {{}}}}{{ {0} {1} {{0}} {{1}} homepage {0}!</name>
68+
<name>Untranslated text</name>
5469
<description/>
5570
<comment/>
5671
<translations>
5772
<translation>
5873
<language>de-DE</language>
59-
<approved>true</approved>
74+
<approved>false</approved>
6075
</translation>
6176
<translation>
6277
<language>en-US</language>
63-
<approved>true</approved>
78+
<approved>false</approved>
6479
</translation>
6580
</translations>
6681
</concept_node>

example/locales/de.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
2-
"ABC {0} DEF": "Deutsches ABC {0} DEF",
32
"Hello world!": "Hallo Welt!",
4-
"Welcome to the {{}}}}{{ {0} {1} {{0}} {{1}} homepage {0}!": "Willkommen zur {{}}}}{{ {0} {1} {{0}} {{1}} Homepage {0}!"
3+
"Lazy term": "Fauler Begriff",
4+
"This text contains {0} \\{} curly braces and \\\\{\\{}}\\{0}.": "Dieser Text enthält {0} \\{} geschweifte Klammern und \\\\{\\{}}\\{0}.",
5+
"Untranslated text": ""
56
}

example/locales/en.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
2-
"ABC {0} DEF": "ABC {0} DEF",
32
"Hello world!": "Hello world!",
4-
"Welcome to the {{}}}}{{ {0} {1} {{0}} {{1}} homepage {0}!": "Welcome to the {{}}}}{{ {0} {1} {{0}} {{1}} homepage {0}!"
3+
"Lazy term": "Lazy term",
4+
"This text contains {0} \\{} curly braces and \\\\{\\{}}\\{0}.": "This text contains {0} \\{} curly braces and \\\\{\\{}}\\{0}.",
5+
"Untranslated text": "Untranslated text"
56
}

example/main.tsx

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,43 @@
11
import { Hono } from "@hono/hono";
22
import { jsxRenderer } from "@hono/hono/jsx-renderer";
3-
// import { languageDetector } from '@hono/hono/language';
4-
import { t } from "@wuespace/honolate";
3+
import { lt, t, useLocale } from "@wuespace/honolate";
54
import { withI18n } from "./i18n.ts";
65

7-
const app = new Hono();
6+
const lazyTerm = lt`Lazy term`;
87

9-
app.use(
10-
"*",
11-
// languageDetector({
12-
// supportedLanguages: ['en', 'ar', 'ja', 'de'], // Must include fallback
13-
// fallbackLanguage: 'en', // Required
14-
// }),
15-
withI18n,
16-
jsxRenderer(),
17-
);
8+
export const app = new Hono()
9+
.use(
10+
withI18n,
11+
jsxRenderer(),
12+
)
13+
.get("/text", (c) => c.text(t`Hello world!`))
14+
.get("/locale", (c) => c.text(useLocale()))
15+
.get("/render", (c) => c.render(<h1>{t`Hello world!`}</h1>))
16+
.get("/component", (c) => c.render(<Component />))
17+
.get("/async-component", (c) => {
18+
return c.render(<AsyncComponent />);
19+
})
20+
.get("/async-component-alt", async (c) => {
21+
const component = await AsyncComponent();
22+
return c.render(component);
23+
})
24+
.get("/untranslated", (c) => c.text(t`Untranslated text`))
25+
.get("/lazy", (c) => c.text(t(lazyTerm)))
26+
.get(
27+
"/escape-test",
28+
(c) => c.text(t`This text contains ${1} {} curly braces and \\{{}}{0}.`),
29+
)
30+
.notFound((c) => c.text("Not Found", 404));
1831

19-
app.get("/", (c) => {
20-
return c.render(
21-
<div>
22-
{t`Welcome to the {{}}}}{{ {0} {1} {{0}} {{1}} homepage ${c.req.url}!`}
23-
{t`Hello world!`}
24-
{t`Test: ${<code>{t`Hello!`}</code>}`}
25-
<LocalePrinter />
26-
</div>,
27-
);
28-
});
32+
import.meta.main && Deno.serve(app.fetch);
2933

30-
function LocalePrinter() {
31-
const locale = t`ABC ${3} DEF`;
32-
return <div>Current locale: {locale}</div>;
34+
function Component() {
35+
const greeting = t`Hello world!`;
36+
return <h1>{greeting}</h1>;
3337
}
3438

35-
Deno.serve(app.fetch);
39+
async function AsyncComponent() {
40+
await Promise.resolve();
41+
const greeting = t`Hello world!`;
42+
return <h1>{greeting}</h1>;
43+
}

tests/hono-e2e.test.ts

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { testClient } from "@hono/hono/testing";
2+
import { expect } from "@std/expect";
3+
import { describe, it } from "node:test";
4+
import { app } from "../example/main.tsx";
5+
6+
const testApp = testClient(app);
7+
8+
describe("Hono + Honolate E2E", () => {
9+
describe("t function in different contexts", () => {
10+
const paths = [
11+
"text",
12+
"render",
13+
"component",
14+
"async-component",
15+
"async-component-alt",
16+
] as const;
17+
for (const path of paths) {
18+
it(`GET /${path} should return localized 'Hello world!'`, async () => {
19+
const resDefault = await (await testApp[path].$get({})).text();
20+
const resEn = await (await testApp[path].$get({
21+
query: { lang: "en" },
22+
})).text();
23+
const resDe = await (await testApp[path].$get({
24+
query: { lang: "de" },
25+
})).text();
26+
27+
expect(resDefault).toContain("Hello world!");
28+
expect(resEn).toContain("Hello world!");
29+
expect(resDe).toContain("Hallo Welt!");
30+
});
31+
}
32+
});
33+
describe("Untranslated text", () => {
34+
it("GET /untranslated should return untranslated text", async () => {
35+
const resDefault = await (await testApp.untranslated.$get({})).text();
36+
const resEn = await (await testApp.untranslated.$get({
37+
query: { lang: "en" },
38+
})).text();
39+
const resDe = await (await testApp.untranslated.$get({
40+
query: { lang: "de" },
41+
})).text();
42+
43+
expect(resDefault).toBe("Untranslated text");
44+
expect(resEn).toBe("Untranslated text");
45+
expect(resDe).toBe("Untranslated text");
46+
});
47+
});
48+
describe("Lazy translation term", () => {
49+
it("GET /lazy should return localized lazy term", async () => {
50+
const resDefault = await (await testApp.lazy.$get({})).text();
51+
const resEn = await (await testApp.lazy.$get({
52+
query: { lang: "en" },
53+
})).text();
54+
const resDe = await (await testApp.lazy.$get({
55+
query: { lang: "de" },
56+
})).text();
57+
58+
expect(resDefault).toBe("Lazy term");
59+
expect(resEn).toBe("Lazy term");
60+
expect(resDe).toBe("Fauler Begriff");
61+
});
62+
});
63+
describe("Escape test", () => {
64+
it("GET /escape-test should return correctly escaped text", async () => {
65+
const res = await (await testApp["escape-test"].$get({})).text();
66+
expect(res).toBe("This text contains 1 {} curly braces and \\{{}}{0}.");
67+
const resDe = await (await testApp["escape-test"].$get({
68+
query: { lang: "de" },
69+
})).text();
70+
expect(resDe).toBe(
71+
"Dieser Text enthält 1 {} geschweifte Klammern und \\{{}}{0}.",
72+
);
73+
});
74+
});
75+
describe("Locale", () => {
76+
it("GET /locale should return correct locale", async () => {
77+
const resDefault = await (await testApp.locale.$get({})).text();
78+
const resEn = await (await testApp.locale.$get({
79+
query: { lang: "en" },
80+
})).text();
81+
const resDe = await (await testApp.locale.$get({
82+
query: { lang: "de" },
83+
})).text();
84+
85+
expect(resDefault).toBe("en");
86+
expect(resEn).toBe("en");
87+
expect(resDe).toBe("de");
88+
});
89+
});
90+
});

0 commit comments

Comments
 (0)