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
105 changes: 55 additions & 50 deletions config/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,24 +159,28 @@ export default defineConfig(({ mode }) => {
debug: process.env.NODE_ENV === 'development',
basePath: 'src/plugin/available',
}),
istanbul({
extension: ['.js', '.ts', '.jsx', '.tsx'],
requireEnv: true,
cypress: true,
include: [
'src/screens/**/*.{js,jsx,ts,tsx}',
'src/components/**/*.{js,jsx,ts,tsx}',
'src/subComponents/**/*.{js,jsx,ts,tsx}',
],
exclude: [
'node_modules/**',
'cypress/**',
'coverage/**',
'.nyc_output/**',
'src/**/*.spec.{ts,tsx,js,jsx}',
'src/**/__tests__/**',
],
}),
...(process.env.CYPRESS_COVERAGE === 'true'
? [
istanbul({
extension: ['.js', '.ts', '.jsx', '.tsx'],
requireEnv: true,
cypress: true,
include: [
'src/screens/**/*.{js,jsx,ts,tsx}',
'src/components/**/*.{js,jsx,ts,tsx}',
'src/subComponents/**/*.{js,jsx,ts,tsx}',
],
exclude: [
'node_modules/**',
'cypress/**',
'coverage/**',
'.nyc_output/**',
'src/**/*.spec.{ts,tsx,js,jsx}',
'src/**/__tests__/**',
],
}),
]
: []),
],
// Development server configuration
server: {
Expand All @@ -203,42 +207,43 @@ export default defineConfig(({ mode }) => {
secure: false,
ws: true,
configure: (proxy) => {
// Log outgoing request
proxy.on('proxyReq', (proxyReq, req) => {
console.log('\n[PROXY REQUEST]');
console.log('Method:', req.method);
console.log('URL:', req.url);
console.log('Target:', apiTarget + req.url);
console.log('Headers:', JSON.stringify(req.headers, null, 2));

// Check if body exists and log it
let body = '';
req.on('data', (chunk) => {
body += chunk.toString();
});
req.on('end', () => {
if (body) {
console.log('Body:', body);
}
});
});
const verbose = env.ALLOW_LOGS === 'true';

// Log response
proxy.on('proxyRes', (proxyRes, req) => {
console.log('\n[PROXY RESPONSE]');
console.log('Status:', proxyRes.statusCode);
console.log('URL:', req.url);
if (verbose) {
proxy.on('proxyReq', (proxyReq, req) => {
console.log('\n[PROXY REQUEST]');
console.log('Method:', req.method);
console.log('URL:', req.url);
console.log('Target:', apiTarget + req.url);
console.log('Headers:', JSON.stringify(req.headers, null, 2));

let responseBody = '';
proxyRes.on('data', (chunk) => {
responseBody += chunk.toString();
let body = '';
req.on('data', (chunk) => {
body += chunk.toString();
});
req.on('end', () => {
if (body) {
console.log('Body:', body);
}
});
});
proxyRes.on('end', () => {
if (responseBody) {
console.log('Response Body:', responseBody);
}

proxy.on('proxyRes', (proxyRes, req) => {
console.log('\n[PROXY RESPONSE]');
console.log('Status:', proxyRes.statusCode);
console.log('URL:', req.url);

let responseBody = '';
proxyRes.on('data', (chunk) => {
responseBody += chunk.toString();
});
proxyRes.on('end', () => {
if (responseBody) {
console.log('Response Body:', responseBody);
}
});
});
});
}

proxy.on('error', (err) => {
console.error('\n[PROXY ERROR]', err.message);
Expand Down
17 changes: 5 additions & 12 deletions src/components/AdminPortal/Advertisements/Advertisements.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -349,8 +349,6 @@ describe('Testing Advertisement Component', () => {

await wait();
expect(screen.getByTestId('searchname')).toBeInTheDocument();
expect(screen.getByTestId('searchButton')).toBeInTheDocument();

expect(screen.getByTestId('searchname')).toHaveAttribute(
'placeholder',
translations.searchAdvertisements,
Expand All @@ -376,10 +374,9 @@ describe('Testing Advertisement Component', () => {
await wait();

expect(screen.getByTestId('searchname')).toBeInTheDocument();
expect(screen.getByTestId('searchButton')).toBeInTheDocument();
await userEvent.clear(screen.getByTestId('searchname'));
await userEvent.type(screen.getByTestId('searchname'), 'Cookie shop 6');
await userEvent.click(screen.getByTestId('searchButton'));
await userEvent.keyboard('{Enter}');

await wait();
expect(screen.getByText('Cookie shop 6')).toBeInTheDocument();
Expand Down Expand Up @@ -409,14 +406,13 @@ describe('Testing Advertisement Component', () => {
await wait();

expect(screen.getByTestId('searchname')).toBeInTheDocument();
expect(screen.getByTestId('searchButton')).toBeInTheDocument();

await userEvent.clear(screen.getByTestId('searchname'));
await userEvent.type(
screen.getByTestId('searchname'),
'this is an active advertisement 6',
);
await userEvent.click(screen.getByTestId('searchButton'));
await userEvent.keyboard('{Enter}');

await wait();
expect(screen.getByText('Cookie shop 6')).toBeInTheDocument();
Expand Down Expand Up @@ -446,10 +442,9 @@ describe('Testing Advertisement Component', () => {
await wait();

expect(screen.getByTestId('searchname')).toBeInTheDocument();
expect(screen.getByTestId('searchButton')).toBeInTheDocument();
await userEvent.clear(screen.getByTestId('searchname'));
await userEvent.type(screen.getByTestId('searchname'), 'Cookie shop 6');
await userEvent.click(screen.getByTestId('searchButton'));
await userEvent.keyboard('{Enter}');

await wait();
expect(screen.getByText('Cookie shop 6')).toBeInTheDocument();
Expand Down Expand Up @@ -479,13 +474,12 @@ describe('Testing Advertisement Component', () => {
await wait();

expect(screen.getByTestId('searchname')).toBeInTheDocument();
expect(screen.getByTestId('searchButton')).toBeInTheDocument();
await userEvent.clear(screen.getByTestId('searchname'));
await userEvent.type(
screen.getByTestId('searchname'),
'this is a completed advertisement 6',
);
await userEvent.click(screen.getByTestId('searchButton'));
await userEvent.keyboard('{Enter}');

await wait();
expect(screen.getByText('Cookie shop 6')).toBeInTheDocument();
Expand Down Expand Up @@ -515,10 +509,9 @@ describe('Testing Advertisement Component', () => {
await wait();

expect(screen.getByTestId('searchname')).toBeInTheDocument();
expect(screen.getByTestId('searchButton')).toBeInTheDocument();
await userEvent.clear(screen.getByTestId('searchname'));
await userEvent.type(screen.getByTestId('searchname'), 'BandhanSearchedIt');
await userEvent.click(screen.getByTestId('searchButton'));
await userEvent.keyboard('{Enter}');
expect(
screen.getAllByText('Ads not present for this campaign.'),
).toHaveLength(2); // both completed and active tab
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
import { REMOVE_MEMBER_MUTATION_PG } from 'GraphQl/Mutations/mutations';
import { store } from 'state/store';
import { NotificationToast } from 'components/NotificationToast/NotificationToast';
import type { InterfaceSearchFilterBarAdvanced } from 'types/shared-components/SearchFilterBar/interface';
import type { InterfaceToolbarProps } from 'types/shared-components/Toolbar/interface';

vi.mock('components/NotificationToast/NotificationToast', () => ({
NotificationToast: {
Expand All @@ -45,35 +45,28 @@ vi.mock('./addMember/AddMember', () => ({
),
}));

vi.mock(
'shared-components/SearchFilterBar/SearchFilterBar',
async (importOriginal) => {
const actual =
await importOriginal<
typeof import('shared-components/SearchFilterBar/SearchFilterBar')
>();
return {
default: (props: React.ComponentProps<typeof actual.default>) => (
<>
<actual.default {...props} />
<button
type="button"
data-testid="trigger-invalid-sort"
onClick={() => {
if (props.hasDropdowns) {
(
props as InterfaceSearchFilterBarAdvanced
).dropdowns?.[0]?.onOptionChange?.('invalid');
}
}}
>
Invalid Sort
</button>
</>
),
};
},
);
vi.mock('shared-components/Toolbar/Toolbar', async (importOriginal) => {
const actual =
await importOriginal<typeof import('shared-components/Toolbar/Toolbar')>();
return {
default: (props: InterfaceToolbarProps) => (
<>
<actual.default {...props} />
<button
type="button"
data-testid="trigger-invalid-sort"
onClick={() => {
const handler = props.filters?.[0]?.onChange;
if (!handler) throw new Error('Expected filter onChange handler');
handler('invalid');
}}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
>
Invalid Sort
</button>
</>
),
};
});

vi.mock('shared-components/BreadcrumbsComponent/SafeBreadcrumbs', () => ({
default: ({
Expand Down
16 changes: 11 additions & 5 deletions src/screens/AdminPortal/SubTags/SubTags.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import React from 'react';
import { MockedProvider } from '@apollo/react-testing';
import type { RenderResult } from '@testing-library/react';
import { act, cleanup, render, screen, waitFor } from '@testing-library/react';
import {
act,
cleanup,
fireEvent,
render,
screen,
waitFor,
} from '@testing-library/react';
Comment on lines +4 to +11

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify restricted fireEvent usage in spec files and inspect Enter-triggered search sites
rg -n --type tsx '\bfireEvent\b|keyboard\(\s*[`'\'']\{Enter\}[`'\'']\s*\)'

Repository: PalisadoesFoundation/talawa-admin

Length of output: 104


🏁 Script executed:

fd SubTags.spec.tsx --type f

Repository: PalisadoesFoundation/talawa-admin

Length of output: 125


🏁 Script executed:

cat -n src/screens/AdminPortal/SubTags/SubTags.spec.tsx | head -50

Repository: PalisadoesFoundation/talawa-admin

Length of output: 1963


🏁 Script executed:

sed -n '240,260p' src/screens/AdminPortal/SubTags/SubTags.spec.tsx

Repository: PalisadoesFoundation/talawa-admin

Length of output: 826


🏁 Script executed:

sed -n '235,265p' src/screens/AdminPortal/SubTags/SubTags.spec.tsx

Repository: PalisadoesFoundation/talawa-admin

Length of output: 1184


🏁 Script executed:

rg -n 'fireEvent' src/screens/AdminPortal/SubTags/SubTags.spec.tsx

Repository: PalisadoesFoundation/talawa-admin

Length of output: 167


🏁 Script executed:

sed -n '1,30p' src/screens/AdminPortal/SubTags/SubTags.spec.tsx | grep -E 'import.*user|fireEvent'

Repository: PalisadoesFoundation/talawa-admin

Length of output: 142


🏁 Script executed:

rg -n 'afterEach|cleanup\(\)|vi.restoreAllMocks|vi.clearAllMocks' src/screens/AdminPortal/SubTags/SubTags.spec.tsx | head -20

Repository: PalisadoesFoundation/talawa-admin

Length of output: 299


🏁 Script executed:

sed -n '135,150p' src/screens/AdminPortal/SubTags/SubTags.spec.tsx

Repository: PalisadoesFoundation/talawa-admin

Length of output: 466


🏁 Script executed:

sed -n '235,275p' src/screens/AdminPortal/SubTags/SubTags.spec.tsx

Repository: PalisadoesFoundation/talawa-admin

Length of output: 1602


🏁 Script executed:

grep -n 'wait()' src/screens/AdminPortal/SubTags/SubTags.spec.tsx | head -5

Repository: PalisadoesFoundation/talawa-admin

Length of output: 186


🏁 Script executed:

sed -n '80,100p' src/screens/AdminPortal/SubTags/SubTags.spec.tsx

Repository: PalisadoesFoundation/talawa-admin

Length of output: 583


🏁 Script executed:

sed -n '139,145p' src/screens/AdminPortal/SubTags/SubTags.spec.tsx

Repository: PalisadoesFoundation/talawa-admin

Length of output: 261


🏁 Script executed:

grep -n "^const wait\|^function wait\|^export.*wait" src/screens/AdminPortal/SubTags/SubTags.spec.tsx

Repository: PalisadoesFoundation/talawa-admin

Length of output: 59


🏁 Script executed:

rg -n "import.*wait|const wait|function wait" src/screens/AdminPortal/SubTags/SubTags.spec.tsx

Repository: PalisadoesFoundation/talawa-admin

Length of output: 126


🏁 Script executed:

sed -n '61,65p' src/screens/AdminPortal/SubTags/SubTags.spec.tsx

Repository: PalisadoesFoundation/talawa-admin

Length of output: 220


🏁 Script executed:

sed -n '245,260p' src/screens/AdminPortal/SubTags/SubTags.spec.tsx

Repository: PalisadoesFoundation/talawa-admin

Length of output: 707


❌ Critical: Replace hardcoded wait() function and fireEvent.change() with deterministic async patterns.

Two issues compound test flakiness in CI sharding:

  1. Hardcoded delay (line 61): The wait(ms = 500) helper uses setTimeout, creating race conditions in variable-latency CI. The multiple await wait() calls throughout this file (e.g., lines 147, 155, 163) prevent deterministic test execution.

  2. Mixed userEvent + fireEvent (line 250): Using fireEvent.change() with await user.keyboard() is inconsistent and can fail if focus is lost between operations.

Proposed fixes

Fix 1 (line 61-66): Replace hardcoded wait helper:

-async function wait(ms = 500): Promise<void> {
-  await act(() => {
-    return new Promise((resolve) => {
-      setTimeout(resolve, ms);
-    });
-  });
-}
+// Removed: Use waitFor/findBy queries instead for deterministic waits

Then replace all await wait() calls with waitFor() or async queries (e.g., screen.findByPlaceholderText()).

Fix 2 (lines 249-251): Replace fireEvent with userEvent:

-    const input = screen.getByPlaceholderText(translations.searchByName);
-    fireEvent.change(input, { target: { value: '  searchSubTag  ' } });
+    const input = await screen.findByPlaceholderText(translations.searchByName);
+    await user.click(input);
+    await user.clear(input);
+    await user.paste('  searchSubTag  ');
     await user.keyboard('{Enter}');

Also remove fireEvent from imports (line 7).

Also applies to: All await wait() calls (lines 147, 155, 163, 181, 193, and others). Replace with conditional async queries per guidelines.

🧰 Tools
🪛 ESLint

[error] 7-7: 'fireEvent' import from '@testing-library/react' is restricted. Tests in this file use fireEvent for user interactions; use userEvent from @testing-library/user-event instead.

(no-restricted-imports)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/screens/AdminPortal/SubTags/SubTags.spec.tsx` around lines 4 - 11, The
test uses a fragile hardcoded helper wait() and mixes fireEvent.change() with
user.keyboard(), causing flaky timing; remove the wait helper (symbol: wait) and
replace all await wait() usages with deterministic async queries or waitFor()
(e.g., screen.findByPlaceholderText, screen.findByText) so assertions await the
actual DOM conditions, and replace fireEvent.change(...) usages with userEvent
APIs (e.g., await user.type(...) or await user.clear(...) + user.type(...)) to
keep interactions consistent with user.keyboard(); finally, remove fireEvent
from the imports list to avoid accidental usage and update tests referencing
fireEvent.change to use the userEvent equivalents (look for occurrences around
the user.keyboard() call and tests that previously awaited wait()).

import userEvent from '@testing-library/user-event';
import { I18nextProvider } from 'react-i18next';
import { Provider } from 'react-redux';
Expand Down Expand Up @@ -239,10 +246,9 @@ describe('Organisation Tags Page', () => {
).toBeInTheDocument();
});
const input = screen.getByPlaceholderText(translations.searchByName);
// Test trimming: add spaces that should be trimmed by the component
await user.clear(input);
await user.type(input, ' searchSubTag ');
await user.click(screen.getByTestId('searchBtn'));
// Set value at once to avoid intermediate unmatched queries
fireEvent.change(input, { target: { value: ' searchSubTag ' } });
await user.keyboard('{Enter}');

// should render the two searched tags from the mock data
// where name starts with "searchSubTag" (mocks are configured for this)
Expand Down
Loading
Loading