Skip to content
Merged
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
25 changes: 25 additions & 0 deletions api/changelogs/changelog_v2_3_0 .md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
## Info
### Version
v2.3.0
### Date
2025-19-07
### Autor
James Stark
## Changelog:

### Endpoints
- Add new POST endpoint to matching to enable demo functionality
- Add new GET endpoint to user to enable fetching pre-made demo users


``` diff

@@ POST @ /api/v2/matching/demo @@
+ Add new POST operation with a MatchRequestNew payload
# Generates a match fitting this MatchRequest with placeholder users

@@ Get @ /api/v2/users/demo @@
+ Add new GET operation with no payload that returns demo users
# Returns 3 pre-made demo-users

```
20 changes: 20 additions & 0 deletions api/changelogs/changelog_v2_3_1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
## Info
### Version
v2.3.0
### Date
2025-19-07
### Autor
James Stark
## Changelog:

### Endpoints
- Remove internal tag


``` diff

@@ GET @ /api/v2/users/demo @@
- Remove internal tag
# code-gen does not generate internal

```
2 changes: 1 addition & 1 deletion api/flags/flags.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@

# DO NOT CHANGE
info:
version: 2.2.2
version: 2.3.1
46 changes: 45 additions & 1 deletion api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ x-stoplight:
id: ceylawji1yc2t
info:
title: MeetAtMensa
version: 2.2.2
version: 2.3.1
description: |-
This OpenAPI specification defines the endpoints, schemas, and security mechanisms
for the Meet@Mensa User micro-service.
Expand Down Expand Up @@ -1063,6 +1063,50 @@ paths:
x-stoplight:
id: 3fke7st84x7x9
description: Retrieve a user object based on an Auth0 sub ID
/api/v2/matching/demo:
post:
summary: Create demo request
tags:
- Matching
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/Group'
'409':
description: User already has a meeting on this day!
'500':
description: Internal Server Error
operationId: post-api-v2-matching-demo
x-stoplight:
id: nz0sz8ks59ugw
description: Submit a match request which will be immediately matched with a group of demo users.
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/MatchRequestNew'
/api/v2/users/demo:
get:
summary: Get demo users
tags:
- User
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/UserCollection'
'500':
description: Internal Server Error
operationId: get-api-v2-users-demo
x-stoplight:
id: fq2onjttsvxxa
description: Return 3 demo-users in a UserCollection
x-internal: false
tags:
- name: GenAI
description: Paths belonging to the GenAI microservice
Expand Down
122 changes: 122 additions & 0 deletions client/src/__tests__/components/CreateMatchRequestDialog.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,4 +125,126 @@ describe('CreateMatchRequestDialog', () => {

expect(mockOnClose).toHaveBeenCalled();
});

it('submits demo form with valid data when demo button is clicked', async () => {
const user = userEvent.setup();
const mockOnDemoSubmit = jest.fn();

render(
<CreateMatchRequestDialog
open={true}
onClose={mockOnClose}
onSubmit={mockOnSubmit}
onDemoSubmit={mockOnDemoSubmit}
/>
);

// Fill in location
const locationSelect = screen.getByRole('combobox');
await user.click(locationSelect);
await user.click(screen.getByText('Mensa Garching'));

// Set date
const datePickerButton = screen.getByRole('button', { name: /choose date/i });
await user.click(datePickerButton);
await user.keyboard('{Enter}');

// Select timeslots
const timeslotButtons = screen
.getAllByRole('button')
.filter(
(button) =>
button.textContent?.includes('12:00-12:15') ||
button.textContent?.includes('12:15-12:30') ||
button.textContent?.includes('12:30-12:45')
);

for (const button of timeslotButtons.slice(0, 3)) {
await user.click(button);
}

// Wait for demo button to be enabled
await waitFor(
() => {
const demoButton = screen.getByRole('button', { name: /demo/i });
expect(demoButton).not.toBeDisabled();
},
{ timeout: 5000 }
);

// Click demo button
const demoButton = screen.getByRole('button', { name: /demo/i });
await user.click(demoButton);

await waitFor(() => {
expect(mockOnDemoSubmit).toHaveBeenCalledWith({
userID: 'test-user-id',
location: 'GARCHING',
date: expect.stringMatching(/^[\d]{4}-[\d]{2}-[\d]{2}$/),
timeslot: [9, 10, 11],
preferences: {
degreePref: false,
agePref: false,
genderPref: false,
},
});
});
});

it('falls back to regular submit when demo handler is not provided', async () => {
const user = userEvent.setup();

render(<CreateMatchRequestDialog open={true} onClose={mockOnClose} onSubmit={mockOnSubmit} />);

// Fill in location
const locationSelect = screen.getByRole('combobox');
await user.click(locationSelect);
await user.click(screen.getByText('Mensa Garching'));

// Set date
const datePickerButton = screen.getByRole('button', { name: /choose date/i });
await user.click(datePickerButton);
await user.keyboard('{Enter}');

// Select timeslots
const timeslotButtons = screen
.getAllByRole('button')
.filter(
(button) =>
button.textContent?.includes('12:00-12:15') ||
button.textContent?.includes('12:15-12:30') ||
button.textContent?.includes('12:30-12:45')
);

for (const button of timeslotButtons.slice(0, 3)) {
await user.click(button);
}

// Wait for demo button to be enabled
await waitFor(
() => {
const demoButton = screen.getByRole('button', { name: /demo/i });
expect(demoButton).not.toBeDisabled();
},
{ timeout: 5000 }
);

// Click demo button (should fall back to regular submit)
const demoButton = screen.getByRole('button', { name: /demo/i });
await user.click(demoButton);

await waitFor(() => {
expect(mockOnSubmit).toHaveBeenCalledWith({
userID: 'test-user-id',
location: 'GARCHING',
date: expect.stringMatching(/^[\d]{4}-[\d]{2}-[\d]{2}$/),
timeslot: [9, 10, 11],
preferences: {
degreePref: false,
agePref: false,
genderPref: false,
},
});
});
});
});
105 changes: 105 additions & 0 deletions client/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,46 @@ export interface paths {
patch?: never;
trace?: never;
};
"/api/v2/matching/demo": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
/**
* Create demo request
* @description Submit a match request which will be immediately matched with a group of demo users.
*/
post: operations["post-api-v2-matching-demo"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/v2/users/demo": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* Get demo users
* @description Return 3 demo-users in a UserCollection
*/
get: operations["get-api-v2-users-demo"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
}
export type webhooks = Record<string, never>;
export interface components {
Expand Down Expand Up @@ -1110,4 +1150,69 @@ export interface operations {
};
};
};
"post-api-v2-matching-demo": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: {
content: {
"application/json": components["schemas"]["MatchRequestNew"];
};
};
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["Group"];
};
};
/** @description User already has a meeting on this day! */
409: {
headers: {
[name: string]: unknown;
};
content?: never;
};
/** @description Internal Server Error */
500: {
headers: {
[name: string]: unknown;
};
content?: never;
};
};
};
"get-api-v2-users-demo": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["UserCollection"];
};
};
/** @description Internal Server Error */
500: {
headers: {
[name: string]: unknown;
};
content?: never;
};
};
};
}
Loading
Loading