diff --git a/public/images/banks/logos/wise.png b/public/images/banks/logos/wise.png deleted file mode 100644 index 4df8fad7..00000000 Binary files a/public/images/banks/logos/wise.png and /dev/null differ diff --git a/resources/js/components/open-banking/connect-account-dialog.test.tsx b/resources/js/components/open-banking/connect-account-dialog.test.tsx index b9436e8c..6f398f65 100644 --- a/resources/js/components/open-banking/connect-account-dialog.test.tsx +++ b/resources/js/components/open-banking/connect-account-dialog.test.tsx @@ -70,23 +70,27 @@ function liveBbvaConnection(): BankingConnection { }; } -async function reachBankStep(connections: BankingConnection[]) { +type Institution = { + name: string; + country: string; + logo: string; + maximum_consent_validity: null; +}; + +function institution(name: string, logo = ''): Institution { + return { name, country: 'ES', logo, maximum_consent_validity: null }; +} + +async function reachBankStep( + connections: BankingConnection[], + institutions: Institution[] = [ + institution('BBVA'), + institution('CaixaBank'), + ], +) { global.fetch = vi.fn().mockResolvedValue({ ok: true, - json: async () => [ - { - name: 'BBVA', - country: 'ES', - logo: '', - maximum_consent_validity: null, - }, - { - name: 'CaixaBank', - country: 'ES', - logo: '', - maximum_consent_validity: null, - }, - ], + json: async () => institutions, }) as unknown as typeof fetch; render( @@ -104,7 +108,7 @@ async function reachBankStep(connections: BankingConnection[]) { await waitFor(() => expect( - screen.getByRole('button', { name: /BBVA/ }), + screen.getByPlaceholderText('Search banks...'), ).toBeInTheDocument(), ); } @@ -192,4 +196,34 @@ describe('ConnectAccountDialog', () => { ).not.toBeInTheDocument(); expect(screen.getByRole('button', { name: 'Connect' })).toBeEnabled(); }); + + it('shows Wise once, preferring the native integration over the aggregator', async () => { + await reachBankStep( + [], + [institution('Abanca'), institution('Wise', 'aggregator-logo')], + ); + + expect(screen.getAllByText('Wise')).toHaveLength(1); + // The surviving entry is the native provider, with its own logo — + // not the aggregator's. + const wiseButton = screen.getByRole('button', { name: 'Wise' }); + expect(wiseButton.querySelector('img')).toHaveAttribute( + 'src', + 'https://enablebanking.com/brands/BE/Wise/', + ); + }); + + it('does not duplicate banks when the search is filtered repeatedly', async () => { + await reachBankStep( + [], + [institution('Abanca'), institution('Wise', 'aggregator-logo')], + ); + const search = screen.getByPlaceholderText('Search banks...'); + + for (const query of ['wise', '', 'wise', '']) { + fireEvent.change(search, { target: { value: query } }); + } + + expect(screen.getAllByText('Wise')).toHaveLength(1); + }); }); diff --git a/resources/js/components/open-banking/connect-account-dialog.tsx b/resources/js/components/open-banking/connect-account-dialog.tsx index c7d52ecc..b6b8cea5 100644 --- a/resources/js/components/open-banking/connect-account-dialog.tsx +++ b/resources/js/components/open-banking/connect-account-dialog.tsx @@ -149,41 +149,46 @@ export function ConnectAccountDialog({ />
- {filteredInstitutions.map((institution) => { - const isConnected = connectedBankNames.has( - institution.name, - ); + {filteredInstitutions.map( + (institution, index) => { + const isConnected = + connectedBankNames.has( + institution.name, + ); - return ( - - ); - })} + return ( + + ); + }, + )} {filteredInstitutions.length === 0 && (

{__('No banks found.')} diff --git a/resources/js/components/open-banking/connect-account-inline.tsx b/resources/js/components/open-banking/connect-account-inline.tsx index 257798d1..9dc7f636 100644 --- a/resources/js/components/open-banking/connect-account-inline.tsx +++ b/resources/js/components/open-banking/connect-account-inline.tsx @@ -131,9 +131,9 @@ export function ConnectAccountInline({ />

- {filteredInstitutions.map((institution) => ( + {filteredInstitutions.map((institution, index) => (