Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions app/components/AddMenuButton.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@ import {
Icon,
} from '@chakra-ui/react';
import { LuPlus } from 'react-icons/lu';
import { useNavigate } from 'react-router';
import { useLocation } from 'react-router';

// On a studios or associations list, a new organisation starts as that type (#86).
const ORG_TYPE_BY_PATH = { '/studios': 'studio', '/associations': 'association' };

const AddMenuButton = () => {
const navigate = useNavigate();
const { pathname } = useLocation();
const orgType = ORG_TYPE_BY_PATH[pathname];

return (
<Menu.Root>
Expand All @@ -28,13 +32,13 @@ const AddMenuButton = () => {
<Menu.Positioner>
<Menu.Content>
<Menu.Item _hover={{ textDecor: 'none' }} value="item-0" asChild>
<ChakraLink href="games/create">Add game</ChakraLink>
<ChakraLink href="/games/create">Add game</ChakraLink>
</Menu.Item>
<Menu.Item _hover={{ textDecor: 'none' }} value="item-1" asChild>
<ChakraLink href="/events/create">Add event</ChakraLink>
</Menu.Item>
<Menu.Item _hover={{ textDecor: 'none' }} value="item-2" asChild>
<ChakraLink href="/orgs/create">Add organisation</ChakraLink>
<ChakraLink href={orgType ? `/orgs/create?type=${orgType}` : '/orgs/create'}>Add organisation</ChakraLink>
</Menu.Item>
</Menu.Content>
</Menu.Positioner>
Expand Down
23 changes: 20 additions & 3 deletions app/components/GameForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
import * as yup from 'yup';
import { Input, Button, Textarea, Grid, Field } from '@chakra-ui/react';
import { Input, Button, Textarea, Grid, Field, Link as ChakraLink } from '@chakra-ui/react';

import PossibleGameDuplicates from '../components/PossibleGameDuplicates';

Expand Down Expand Up @@ -73,16 +73,30 @@ const GameForm = ({ defaultData = {}, loading = false, ...rest }) => {
{errors.name && errors.name.message}
</Field.ErrorText>
</Field.Root>
<Field.Root gridColumn="1 / 3" invalid={errors.name}>
<Field.Root gridColumn="1 / 3" invalid={errors.igdb_url}>
<Field.Label>IGDB</Field.Label>
<Input
{...register('igdb_url')}
placeholder="https://www.igdb.com/games/super-tractor-simulator-2042"
type="url"
pattern="https://www.igdb.com\/games\/(.+)"
/>
{newGameName?.trim() && (
<Field.HelperText>
Find its page by{' '}
<ChakraLink
href={`https://www.igdb.com/search?q=${encodeURIComponent(newGameName.trim())}`}
target="_blank"
rel="noopener noreferrer"
textDecoration="underline"
>
searching IGDB for “{newGameName.trim()}”
</ChakraLink>
.
</Field.HelperText>
)}
<Field.ErrorText>
{errors.name && errors.name.message}
{errors.igdb_url && errors.igdb_url.message}
</Field.ErrorText>
</Field.Root>
<Field.Root gridColumn="1 / 3" invalid={errors.about}>
Expand All @@ -105,6 +119,9 @@ const GameForm = ({ defaultData = {}, loading = false, ...rest }) => {
placeholder="https://example.com"
type="url"
/>
<Field.HelperText>
The game's official website, or else its Steam or itch.io page.
</Field.HelperText>
<Field.ErrorText>
{errors.site && errors.site.message}
</Field.ErrorText>
Expand Down
4 changes: 4 additions & 0 deletions app/routes/orgs.create.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ export const loader = async ({ request }) => {
return {
values: {
name: searchParams.get('name') || '',
// Pre-selected from the studios or associations list (#86).
...(['studio', 'association'].includes(searchParams.get('type')) && {
type: searchParams.get('type'),
}),
},
currentUser,
};
Expand Down
13 changes: 13 additions & 0 deletions e2e/games.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,16 @@ test('a game with no studio hides "Made by" from visitors only', async ({ page }
await db.$disconnect();
}
});

// #86: the game form points to an IGDB search for the name, and says which site to give.
test('the game form links to an IGDB search for the name', async ({ page }) => {
await signIn(page, MEMBER);
await page.goto('/games/create');
await expect(page.getByText("The game's official website, or else its Steam or itch.io page.")).toBeVisible();
await expect(page.getByRole('link', { name: /searching IGDB/ })).toHaveCount(0);

await page.getByPlaceholder(/Super Tractor Simulator/).fill('Héros & Co');
const search = page.getByRole('link', { name: 'searching IGDB for “Héros & Co”' });
await expect(search).toHaveAttribute('href', 'https://www.igdb.com/search?q=H%C3%A9ros%20%26%20Co');
await expect(search).toHaveAttribute('target', '_blank');
});
12 changes: 12 additions & 0 deletions e2e/orgs.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
const code = new URL(page.url()).searchParams.get('country');

await page.goto(`/studios?country=${code}`);
await expect(page.getByRole('combobox', { name: 'Country' })).toHaveValue(label);

Check failure on line 41 in e2e/orgs.spec.js

View workflow job for this annotation

GitHub Actions / End-to-end tests

[chromium] › e2e/orgs.spec.js:23:1 › the studios country filter is searchable

1) [chromium] › e2e/orgs.spec.js:23:1 › the studios country filter is searchable ───────────────── Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: expect(locator).toHaveValue(expected) failed Locator: getByRole('combobox', { name: 'Country' }) Expected: "🇧🇶 Bonaire, Saint Eustatius and Saba (1)" Received: "🇧🇶 Bonaire, Saint Eustatius and Saba (1)" Timeout: 5000ms Call log: - Expect "toHaveValue" getByRole('combobox', { name: 'Country' }) with timeout 5000ms - waiting for getByRole('combobox', { name: 'Country' }) 14 × locator resolved to <input dir="ltr" type="text" role="combobox" data-part="input" autocorrect="off" autocomplete="off" spellcheck="false" data-state="closed" data-scope="combobox" autocapitalize="none" aria-expanded="false" aria-autocomplete="list" placeholder="All countries" id="combobox:_R_j9lahn5_:input" class="chakra-combobox__input css-1gutn4" aria-controls="combobox:_R_j9lahn5_:content" value="🇧🇶 Bonaire, Saint Eustatius and Saba (1)"/> - unexpected value "🇧🇶 Bonaire, Saint Eustatius and Saba (1)" 39 | 40 | await page.goto(`/studios?country=${code}`); > 41 | await expect(page.getByRole('combobox', { name: 'Country' })).toHaveValue(label); | ^ 42 | }); 43 | 44 | // #198: an org without games or events shows signed-in users how to add them. at /home/runner/work/community/community/e2e/orgs.spec.js:41:65

Check failure on line 41 in e2e/orgs.spec.js

View workflow job for this annotation

GitHub Actions / End-to-end tests

[chromium] › e2e/orgs.spec.js:23:1 › the studios country filter is searchable

1) [chromium] › e2e/orgs.spec.js:23:1 › the studios country filter is searchable ───────────────── Error: expect(locator).toHaveValue(expected) failed Locator: getByRole('combobox', { name: 'Country' }) Expected: "🇧🇶 Bonaire, Saint Eustatius and Saba (1)" Received: "🇧🇶 Bonaire, Saint Eustatius and Saba (1)" Timeout: 5000ms Call log: - Expect "toHaveValue" getByRole('combobox', { name: 'Country' }) with timeout 5000ms - waiting for getByRole('combobox', { name: 'Country' }) 14 × locator resolved to <input dir="ltr" type="text" role="combobox" data-part="input" autocorrect="off" autocomplete="off" spellcheck="false" data-state="closed" data-scope="combobox" autocapitalize="none" aria-expanded="false" aria-autocomplete="list" placeholder="All countries" id="combobox:_R_j9lahn5_:input" class="chakra-combobox__input css-1gutn4" aria-controls="combobox:_R_j9lahn5_:content" value="🇧🇶 Bonaire, Saint Eustatius and Saba (1)"/> - unexpected value "🇧🇶 Bonaire, Saint Eustatius and Saba (1)" 39 | 40 | await page.goto(`/studios?country=${code}`); > 41 | await expect(page.getByRole('combobox', { name: 'Country' })).toHaveValue(label); | ^ 42 | }); 43 | 44 | // #198: an org without games or events shows signed-in users how to add them. at /home/runner/work/community/community/e2e/orgs.spec.js:41:65
});

// #198: an org without games or events shows signed-in users how to add them.
Expand Down Expand Up @@ -95,3 +95,15 @@
await expect(link).toHaveAttribute('href', 'https://bsky.app/profile/sky-studio.bsky.social');
});
});

// #86: "Add organisation" from the associations list starts an association.
test('adding an organisation from a list pre-selects its type', async ({ page }) => {
await signIn(page, MEMBER);
for (const [list, type] of [['/associations', 'Association'], ['/studios', 'Studio']]) {
await page.goto(list);
await page.getByRole('button', { name: 'Add new' }).click();
await page.getByRole('menuitem', { name: 'Add organisation' }).click();
await expect(page).toHaveURL(`/orgs/create?type=${type.toLowerCase()}`);
await expect(page.getByRole('radio', { name: type })).toBeChecked();
}
});
Loading