Skip to content

Commit

Permalink
add basic crud frontend for clients, tags and projects
Browse files Browse the repository at this point in the history
  • Loading branch information
Gregor Vostrak authored and Onatcer committed Apr 3, 2024
1 parent 7cbfe53 commit 2a7329d
Show file tree
Hide file tree
Showing 77 changed files with 2,670 additions and 330 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ The Zodius HTTP client is generated using the following command:

```bash

npm run generate:zod
npm run zod:generate
```

## Contributing
Expand Down
8 changes: 8 additions & 0 deletions app/Http/Controllers/Api/V1/ClientController.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ protected function checkPermission(Organization $organization, string $permissio
* @return ClientCollection<ClientResource>
*
* @throws AuthorizationException
*
* @operationId getClients
*/
public function index(Organization $organization): ClientCollection
{
Expand All @@ -46,6 +48,8 @@ public function index(Organization $organization): ClientCollection
* Create client
*
* @throws AuthorizationException
*
* @operationId createClient
*/
public function store(Organization $organization, TagStoreRequest $request): ClientResource
{
Expand All @@ -63,6 +67,8 @@ public function store(Organization $organization, TagStoreRequest $request): Cli
* Update client
*
* @throws AuthorizationException
*
* @operationId updateClient
*/
public function update(Organization $organization, Client $client, TagUpdateRequest $request): ClientResource
{
Expand All @@ -78,6 +84,8 @@ public function update(Organization $organization, Client $client, TagUpdateRequ
* Delete client
*
* @throws AuthorizationException
*
* @operationId deleteClient
*/
public function destroy(Organization $organization, Client $client): JsonResponse
{
Expand Down
4 changes: 4 additions & 0 deletions app/Http/Controllers/Api/V1/MemberController.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ class MemberController extends Controller
* @return MemberCollection<MemberResource>>
*
* @throws AuthorizationException
*
* @operationId getMembers
*/
public function index(Organization $organization, MemberIndexRequest $request): MemberCollection
{
Expand All @@ -38,6 +40,8 @@ public function index(Organization $organization, MemberIndexRequest $request):
* Invite a placeholder user to become a member of the organization
*
* @throws AuthorizationException|UserNotPlaceholderApiException
*
* @operationId invitePlaceholder
*/
public function invitePlaceholder(Organization $organization, User $user, Request $request): JsonResponse
{
Expand Down
1 change: 0 additions & 1 deletion e2e/auth.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { expect, test } from '@playwright/test';
import { PLAYWRIGHT_BASE_URL } from '../playwright/config';

async function registerNewUser(page, email, password) {
//await page.getByRole('link', { name: 'Register' }).click();
await page.goto(PLAYWRIGHT_BASE_URL + '/register');
await page.getByLabel('Name').fill('John Doe');
await page.getByLabel('Email').fill(email);
Expand Down
51 changes: 51 additions & 0 deletions e2e/clients.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { expect, Page } from '@playwright/test';
import { PLAYWRIGHT_BASE_URL } from '../playwright/config';
import { test } from '../playwright/fixtures';

async function goToProjectsOverview(page: Page) {
await page.goto(PLAYWRIGHT_BASE_URL + '/clients');
}

// Create new project via modal
test('test that creating and deleting a new client via the modal works', async ({
page,
}) => {
const newClientName =
'New Project ' + Math.floor(1 + Math.random() * 10000);
await goToProjectsOverview(page);
await page.getByRole('button', { name: 'Create Client' }).click();
await page.getByPlaceholder('Client Name').fill(newClientName);
await Promise.all([
page.getByRole('button', { name: 'Create Client' }).nth(1).click(),
page.waitForResponse(
async (response) =>
response.url().includes('/clients') &&
response.request().method() === 'POST' &&
response.status() === 201 &&
(await response.json()).data.id !== null &&
(await response.json()).data.name === newClientName
),
]);

await expect(page.getByTestId('client_table')).toContainText(newClientName);
const moreButton = page.locator(
"[aria-label='Actions for Client " + newClientName + "']"
);
moreButton.click();
const deleteButton = page.locator(
"[aria-label='Delete Client " + newClientName + "']"
);

await Promise.all([
deleteButton.click(),
page.waitForResponse(
async (response) =>
response.url().includes('/clients') &&
response.request().method() === 'DELETE' &&
response.status() === 204
),
]);
await expect(page.getByTestId('client_table')).not.toContainText(
newClientName
);
});
65 changes: 65 additions & 0 deletions e2e/projects.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { expect, Page } from '@playwright/test';
import { PLAYWRIGHT_BASE_URL } from '../playwright/config';
import { test } from '../playwright/fixtures';

async function goToProjectsOverview(page: Page) {
await page.goto(PLAYWRIGHT_BASE_URL + '/projects');
}

// Create new project via modal
test('test that creating and deleting a new project via the modal works', async ({
page,
}) => {
const newProjectName =
'New Project ' + Math.floor(1 + Math.random() * 10000);
await goToProjectsOverview(page);
await page.getByRole('button', { name: 'Create Project' }).click();
await page.getByPlaceholder('Project Name').fill(newProjectName);
await Promise.all([
page.getByRole('button', { name: 'Create Project' }).nth(1).click(),
page.waitForResponse(
async (response) =>
response.url().includes('/projects') &&
response.request().method() === 'POST' &&
response.status() === 201 &&
(await response.json()).data.id !== null &&
(await response.json()).data.color !== null &&
(await response.json()).data.client_id === null &&
(await response.json()).data.name === newProjectName
),
]);

await expect(page.getByTestId('project_table')).toContainText(
newProjectName
);
const moreButton = page.locator(
"[aria-label='Actions for Project " + newProjectName + "']"
);
moreButton.click();
const deleteButton = page.locator(
"[aria-label='Delete Project " + newProjectName + "']"
);

await Promise.all([
deleteButton.click(),
page.waitForResponse(
async (response) =>
response.url().includes('/projects') &&
response.request().method() === 'DELETE' &&
response.status() === 204
),
]);
await expect(page.getByTestId('project_table')).not.toContainText(
newProjectName
);
});

// Create new project with new Client

// Create new project with existing Client

// Delete project via More Options

// Test that project task count is displayed correctly

// Test that active / archive / all filter works (once implemented)
48 changes: 48 additions & 0 deletions e2e/tags.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { expect, Page } from '@playwright/test';
import { PLAYWRIGHT_BASE_URL } from '../playwright/config';
import { test } from '../playwright/fixtures';

async function goToTagsOverview(page: Page) {
await page.goto(PLAYWRIGHT_BASE_URL + '/tags');
}

// Create new project via modal
test('test that creating and deleting a new client via the modal works', async ({
page,
}) => {
const newTagName = 'New Tag ' + Math.floor(1 + Math.random() * 10000);
await goToTagsOverview(page);
await page.getByRole('button', { name: 'Create Tag' }).click();
await page.getByPlaceholder('Tag Name').fill(newTagName);
await Promise.all([
page.getByRole('button', { name: 'Create Tag' }).nth(1).click(),
page.waitForResponse(
async (response) =>
response.url().includes('/tags') &&
response.request().method() === 'POST' &&
response.status() === 201 &&
(await response.json()).data.id !== null &&
(await response.json()).data.name === newTagName
),
]);

await expect(page.getByTestId('tag_table')).toContainText(newTagName);
const moreButton = page.locator(
"[aria-label='Actions for Tag " + newTagName + "']"
);
moreButton.click();
const deleteButton = page.locator(
"[aria-label='Delete Tag " + newTagName + "']"
);

await Promise.all([
deleteButton.click(),
page.waitForResponse(
async (response) =>
response.url().includes('/tags') &&
response.request().method() === 'DELETE' &&
response.status() === 204
),
]);
await expect(page.getByTestId('tag_table')).not.toContainText(newTagName);
});
15 changes: 9 additions & 6 deletions e2e/time.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -428,12 +428,15 @@ test('test that deleting a time entry from the overview works', async ({
test('test that load more works when the end of page is reached', async ({
page,
}) => {
await goToTimeOverview(page);
await page.waitForResponse(
(response) =>
response.url().includes('/time-entries') &&
response.status() === 200
);
await Promise.all([
goToTimeOverview(page),
page.waitForResponse(
(response) =>
response.url().includes('/time-entries') &&
response.status() === 200
),
]);

await page.waitForTimeout(200);
await Promise.all([
page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)),
Expand Down
Loading

0 comments on commit 2a7329d

Please sign in to comment.