From 4e70050ab250417c12dc018d2ae972018ff4cb85 Mon Sep 17 00:00:00 2001 From: Charlie Kolb Date: Mon, 10 Nov 2025 14:26:53 +0200 Subject: [PATCH] fix(editor): Ensure license activation modal works when used without EULA (#21681) --- .../usage/views/SettingsUsageAndPlan.test.ts | 30 ++++++++++++++++++- .../usage/views/SettingsUsageAndPlan.vue | 4 +-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/packages/frontend/editor-ui/src/features/settings/usage/views/SettingsUsageAndPlan.test.ts b/packages/frontend/editor-ui/src/features/settings/usage/views/SettingsUsageAndPlan.test.ts index 9bf2a32ac8a..c649c020b1e 100644 --- a/packages/frontend/editor-ui/src/features/settings/usage/views/SettingsUsageAndPlan.test.ts +++ b/packages/frontend/editor-ui/src/features/settings/usage/views/SettingsUsageAndPlan.test.ts @@ -123,6 +123,34 @@ describe('SettingsUsageAndPlan', () => { expect(container.querySelector('.n8n-badge')).toHaveTextContent('Registered'); }); + it('should correctly call activateLicense on non-eula acceptance', async () => { + usageStore.isLoading = false; + usageStore.planName = 'Community'; + usersStore.currentUser = { + globalScopes: ['license:manage'], + } as IUser; + rbacStore.setGlobalScopes(['license:manage']); + usageStore.activateLicense.mockImplementation(async () => {}); + + const { getByRole } = renderComponent(); + + await userEvent.click(getByRole('button', { name: /activation/i })); + const input = document.querySelector('input') as HTMLInputElement; + await userEvent.type(input, 'test-key-123'); + await userEvent.click(getByRole('button', { name: /activate/i })); + + await waitFor(() => { + expect(usageStore.activateLicense).toHaveBeenCalledTimes(1); + expect(usageStore.activateLicense).toHaveBeenLastCalledWith('test-key-123', undefined); + }); + + expect(mockToast.showMessage).toHaveBeenCalledWith( + expect.objectContaining({ + type: 'success', + }), + ); + }); + describe('License activation with EULA', () => { it('should show EULA modal when activation fails with 400 error and eulaUrl', async () => { usageStore.isLoading = false; @@ -249,7 +277,7 @@ describe('SettingsUsageAndPlan', () => { await userEvent.click(getByRole('button', { name: /activate/i })); await waitFor(() => { - expect(mockToast.showError).toHaveBeenCalledWith(error, expect.any(String)); + expect(mockToast.showError).toHaveBeenCalledWith(error, 'Activation failed'); }); }); }); diff --git a/packages/frontend/editor-ui/src/features/settings/usage/views/SettingsUsageAndPlan.vue b/packages/frontend/editor-ui/src/features/settings/usage/views/SettingsUsageAndPlan.vue index 5af2155f28e..0d7bb2bb4d0 100644 --- a/packages/frontend/editor-ui/src/features/settings/usage/views/SettingsUsageAndPlan.vue +++ b/packages/frontend/editor-ui/src/features/settings/usage/views/SettingsUsageAndPlan.vue @@ -103,7 +103,7 @@ const isEulaError = (error: unknown): error is EulaErrorResponse => { const onLicenseActivation = async (eulaUri?: string) => { try { - await usageStore.activateLicense(activationKey.value, eulaUri); + await usageStore.activateLicense(activationKey.value.trim(), eulaUri?.trim()); activationKeyModal.value = false; eulaModal.value = false; activationKey.value = ''; @@ -321,7 +321,7 @@ const openCommunityRegisterModal = () => { {{ locale.baseText('settings.usageAndPlan.dialog.activation.cancel') }} - + {{ locale.baseText('settings.usageAndPlan.dialog.activation.activate') }}