Skip to content

Commit 36a91f3

Browse files
authored
Merge branch 'main' into add/13991
2 parents 150392d + adcfc32 commit 36a91f3

File tree

7 files changed

+535
-186
lines changed

7 files changed

+535
-186
lines changed

app/[lang]/(hyperjump)/jobs/[id]/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export default async function JobDetail({ params }: JobDetailProps) {
2525

2626
return (
2727
<section className="container mx-auto max-w-5xl border-b px-4 py-8 pt-20 text-black md:px-20 xl:px-0">
28-
<div className="flex flex-col space-y-8 py-12">
28+
<div className="flex flex-col space-y-8 py-12" data-testid="job-detail">
2929
<div>
3030
<p className="text-gray-500">{job.category}</p>
3131
<h1 className="text-5xl font-bold text-gray-800">{job.title}</h1>

app/[lang]/(hyperjump)/jobs/data.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
1-
export const data = {
1+
export type Job = {
2+
id: string;
3+
title: string;
4+
category: string;
5+
description: string;
6+
responsibilities: string[];
7+
requirements: string[];
8+
deliverables: string[];
9+
};
10+
11+
export const data: { jobs: Job[] } = {
212
jobs: [
313
{
414
id: "se-frontend",
Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
1-
import {
2-
supportedLanguages,
3-
type SupportedLanguage
4-
} from "@/locales/.generated/types";
1+
import Link from "next/link";
2+
53
import GridItemsContainer, {
6-
GridItems,
74
GridItemsTitle
85
} from "@/app/components/grid-items";
6+
import {
7+
Card,
8+
CardContent,
9+
CardDescription,
10+
CardHeader,
11+
CardTitle
12+
} from "@/components/ui/card";
13+
import type { SupportedLanguage } from "@/locales/.generated/types";
14+
import { supportedLanguages } from "@/locales/.generated/types";
915

16+
import { type Job } from "./data";
1017
import { data } from "./data";
1118

1219
export const generateStaticParams = async () => {
@@ -18,14 +25,50 @@ type JobProps = {
1825
};
1926

2027
export default async function Home({ params }: JobProps) {
28+
const { lang } = await params;
29+
2130
return (
2231
<GridItemsContainer className="pt-10">
2332
<GridItemsTitle title="Available Positions" />
2433
<div className="mt-5" />
25-
<GridItems
26-
items={data.jobs.map((job) => ({ ...job, url: `/jobs/${job.id}` }))}
27-
lang={(await params).lang}
28-
/>
34+
<JobCards items={data.jobs} lang={lang} />
2935
</GridItemsContainer>
3036
);
3137
}
38+
39+
type JobCardProps = {
40+
items: Job[];
41+
lang: SupportedLanguage;
42+
};
43+
44+
function JobCards({ items, lang }: JobCardProps) {
45+
return (
46+
<div className="grid grid-cols-1 gap-6 md:grid-cols-2 xl:grid-cols-3">
47+
{items.map(({ id, category, description, title }) => (
48+
<Card
49+
key={id}
50+
data-testid={`job-card-${id}`}
51+
className="flex flex-col overflow-hidden rounded-2xl border-[#D9D9D9] bg-white transition-colors duration-300 ease-in-out hover:bg-white/5 hover:shadow-md hover:shadow-white/10">
52+
<CardHeader>
53+
<p className="bg-hyperjump-black/10 text-hyperjump-black mb-2 w-36 rounded-3xl px-2 py-1.5 text-center text-sm font-medium">
54+
{category}
55+
</p>
56+
<Link
57+
href={`/${lang}/jobs/${id}`}
58+
className="transition hover:underline">
59+
<CardTitle className="text-hyperjump-black text-xl font-semibold md:text-[22px]">
60+
{title}
61+
</CardTitle>
62+
</Link>
63+
</CardHeader>
64+
65+
<CardContent className="-mt-3 flex flex-1 flex-col justify-between gap-4">
66+
<CardDescription className="text-base font-medium transition-all duration-300">
67+
{description}
68+
</CardDescription>
69+
</CardContent>
70+
</Card>
71+
))}
72+
</div>
73+
);
74+
}

bun.lock

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

e2e/job.spec.ts

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import { expect, test } from "@playwright/test";
2+
import { data } from "@/app/[lang]/(hyperjump)/jobs/data";
3+
import { supportedLanguages } from "@/locales/.generated/types";
4+
import {
5+
BASE_URL,
6+
footerTest,
7+
gotoAndWait,
8+
headerTest,
9+
imagesTest,
10+
languageSwitcherTest,
11+
metaTest,
12+
responsiveTest
13+
} from "./shared-test";
14+
15+
for (const locale of supportedLanguages) {
16+
const path = `/${locale}/jobs`;
17+
18+
test.describe("Job page", () => {
19+
test.describe(`${locale.toUpperCase()} locale`, () => {
20+
test.beforeEach(async ({ page }) => {
21+
await gotoAndWait(page, `${BASE_URL}${path}`);
22+
});
23+
test.describe("Header", headerTest(locale, path));
24+
test.describe("Language Switching", languageSwitcherTest(locale, path));
25+
test.describe("Images", imagesTest());
26+
test.describe("Footer", footerTest(locale));
27+
test.describe("Meta title and description should exist", metaTest());
28+
test.describe("Responsive Design", responsiveTest(path));
29+
test.describe("Job links", () => {
30+
for (const {
31+
category,
32+
deliverables,
33+
description,
34+
id,
35+
requirements,
36+
responsibilities,
37+
title
38+
} of data.jobs) {
39+
test(`Job ${title} (${category}) should be visible and link to detail page`, async ({
40+
page
41+
}) => {
42+
// job list page
43+
await expect(
44+
page
45+
.getByTestId(`job-card-${id}`)
46+
.getByText(category, { exact: true })
47+
).toBeVisible();
48+
await expect(
49+
page
50+
.getByTestId(`job-card-${id}`)
51+
.getByText(description, { exact: true })
52+
).toBeVisible();
53+
54+
// click on the job link
55+
await page
56+
.getByTestId(`job-card-${id}`)
57+
.getByRole("link", { name: title })
58+
.click();
59+
await page.waitForURL(new RegExp(`${path}/${id}`));
60+
61+
// job detail page
62+
await expect(
63+
page
64+
.getByTestId("job-detail")
65+
.getByText(category, { exact: true })
66+
).toBeVisible();
67+
await expect(
68+
page.getByRole("heading", { name: title })
69+
).toBeVisible();
70+
await expect(
71+
page
72+
.getByTestId("job-detail")
73+
.getByText(description, { exact: true })
74+
).toBeVisible();
75+
for (const responsibility of responsibilities) {
76+
await expect(
77+
page
78+
.getByTestId("job-detail")
79+
.getByText(responsibility, { exact: true })
80+
).toBeVisible();
81+
}
82+
for (const requirement of requirements) {
83+
await expect(
84+
page
85+
.getByTestId("job-detail")
86+
.getByText(requirement, { exact: true })
87+
).toBeVisible();
88+
}
89+
for (const deliverable of deliverables) {
90+
await expect(
91+
page
92+
.getByTestId("job-detail")
93+
.getByText(deliverable, { exact: true })
94+
).toBeVisible();
95+
}
96+
await expect(
97+
page.getByRole("link", { name: "Apply" })
98+
).toBeVisible();
99+
100+
await page.goBack();
101+
await page.waitForURL(new RegExp(path));
102+
});
103+
}
104+
});
105+
});
106+
});
107+
}

0 commit comments

Comments
 (0)