test: improve

This commit is contained in:
Johannes Millan 2025-08-05 19:59:23 +02:00
parent f56f24efe9
commit f330061281
8 changed files with 81 additions and 157 deletions

View file

@ -16,7 +16,6 @@ export const waitForPluginAssets = async (
if (process.env.CI) {
maxRetries = 20;
retryDelay = 3000;
console.log('[Plugin Test] CI environment detected, using extended timeouts');
// Wait for server to be fully ready in CI
await page.waitForLoadState('networkidle');
await page.locator('app-root').waitFor({ state: 'visible', timeout: 15000 });
@ -27,8 +26,6 @@ export const waitForPluginAssets = async (
const baseUrl = page.url().split('#')[0];
const testUrl = `${baseUrl}assets/bundled-plugins/api-test-plugin/manifest.json`;
console.log(`[Plugin Test] Checking plugin assets availability at: ${testUrl}`);
// First ensure the app is loaded
try {
await page.waitForSelector('app-root', { state: 'visible', timeout: 30000 });
@ -36,38 +33,29 @@ export const waitForPluginAssets = async (
state: 'attached',
timeout: 20000,
});
console.log('[Plugin Test] App is loaded');
} catch (e) {
console.error('[Plugin Test] App not fully loaded:', e.message);
throw new Error('[Plugin Test] App not fully loaded:', e.message);
}
for (let i = 0; i < maxRetries; i++) {
try {
const response = await page.request.get(testUrl);
if (response.ok()) {
const manifest = await response.json();
console.log(`[Plugin Test] Plugin manifest loaded successfully:`, manifest.id);
await response.json();
return true;
} else {
console.log(
`[Plugin Test] Attempt ${i + 1}/${maxRetries}: HTTP ${response.status()}`,
);
// Debug: Check if basic assets work
if (response.status() === 404 && i === 3) {
const iconUrl = `${baseUrl}assets/icons/sp.svg`;
try {
const iconResponse = await page.request.get(iconUrl);
console.log(
`[Plugin Test] Basic asset test (${iconUrl}): ${iconResponse.status()}`,
);
await page.request.get(iconUrl);
} catch (e) {
console.log(`[Plugin Test] Basic asset test failed:`, e.message);
console.error(`[Plugin Test] Basic asset test failed:`, e.message);
}
}
}
} catch (error) {
console.log(
console.error(
`[Plugin Test] Attempt ${i + 1}/${maxRetries}: Error - ${error.message}`,
);
}
@ -93,45 +81,36 @@ export const waitForPluginAssets = async (
/**
* Wait for plugin system to be initialized
*/
export const waitForPluginSystemInit = async (
export const waitForPluginManagementInit = async (
page: Page,
timeout: number = 30000,
): Promise<boolean> => {
console.log('[Plugin Test] Waiting for plugin system initialization...');
// Check if plugin system is initialized by looking for plugin management in settings
const result = await page.waitForFunction(
() => {
// Check if we can access the Angular app
const appRoot = document.querySelector('app-root');
if (!appRoot) {
throw new Error('No root');
}
try {
// Check if plugin system is initialized by looking for plugin management in settings
const result = await page.waitForFunction(
() => {
// Check if we can access the Angular app
const appRoot = document.querySelector('app-root');
if (!appRoot) {
console.log('[Plugin Test] App root not found');
return false;
}
// Check if plugin service exists in Angular's injector (if accessible)
// This is a more indirect check since we can't directly access Angular internals
const hasPluginElements =
document.querySelector('plugin-management') !== null ||
document.querySelector('plugin-menu') !== null ||
document.querySelector('[class*="plugin"]') !== null;
// Check if plugin service exists in Angular's injector (if accessible)
// This is a more indirect check since we can't directly access Angular internals
const hasPluginElements =
document.querySelector('plugin-management') !== null ||
document.querySelector('plugin-menu') !== null ||
document.querySelector('[class*="plugin"]') !== null;
if (!hasPluginElements) {
throw new Error('Plugin management not ready');
}
if (hasPluginElements) {
console.log('[Plugin Test] Plugin elements detected');
}
return hasPluginElements;
},
{ timeout },
);
return hasPluginElements;
},
{ timeout },
);
console.log('[Plugin Test] Plugin system initialized');
return !!result;
} catch (error) {
console.error('[Plugin Test] Plugin system initialization timeout:', error.message);
return false;
}
return !!result;
};
/**
@ -142,8 +121,6 @@ export const enablePluginWithVerification = async (
pluginName: string,
timeout: number = 15000,
): Promise<boolean> => {
console.log(`[Plugin Test] Attempting to enable plugin: ${pluginName}`);
const startTime = Date.now();
// First, verify the plugin card exists
@ -157,7 +134,6 @@ export const enablePluginWithVerification = async (
});
if (targetCard) {
console.log(`[Plugin Test] Found plugin card for: ${name}`);
return true;
}
return false;
@ -195,9 +171,6 @@ export const enablePluginWithVerification = async (
const wasEnabled = toggle.getAttribute('aria-checked') === 'true';
if (!wasEnabled) {
toggle.click();
console.log(`[Plugin Test] Clicked toggle to enable ${name}`);
} else {
console.log(`[Plugin Test] ${name} was already enabled`);
}
return { success: true, wasEnabled };
@ -227,7 +200,6 @@ export const enablePluginWithVerification = async (
{ timeout: timeout - (Date.now() - startTime) },
);
console.log(`[Plugin Test] Plugin ${pluginName} enabled successfully`);
return true;
};
@ -239,8 +211,6 @@ export const waitForPluginInMenu = async (
pluginName: string,
timeout: number = 20000,
): Promise<boolean> => {
console.log(`[Plugin Test] Waiting for ${pluginName} to appear in menu...`);
try {
// Navigate to main view to see the menu
await page.goto('/#/tag/TODAY');
@ -256,7 +226,6 @@ export const waitForPluginInMenu = async (
(name) => {
const pluginMenu = document.querySelector('plugin-menu');
if (!pluginMenu) {
console.log('[Plugin Test] Plugin menu not found');
return false;
}
@ -266,17 +235,12 @@ export const waitForPluginInMenu = async (
return text.includes(name);
});
if (found) {
console.log(`[Plugin Test] Found ${name} in plugin menu`);
}
return found;
},
pluginName,
{ timeout },
);
console.log(`[Plugin Test] Plugin ${pluginName} is available in menu`);
return !!result;
} catch (error) {
console.error(`[Plugin Test] Plugin ${pluginName} not found in menu:`, error.message);
@ -288,7 +252,7 @@ export const waitForPluginInMenu = async (
* Debug helper to log current plugin state
*/
export const logPluginState = async (page: Page): Promise<void> => {
const state = await page.evaluate(() => {
await page.evaluate(() => {
const cards = Array.from(document.querySelectorAll('plugin-management mat-card'));
const plugins = cards.map((card) => {
const title =
@ -312,7 +276,7 @@ export const logPluginState = async (page: Page): Promise<void> => {
};
});
console.log('[Plugin Test] Current plugin state:', JSON.stringify(state, null, 2));
// Plugin state debugging removed to reduce test output
};
/**

View file

@ -1,9 +1,9 @@
import { test, expect } from '../../fixtures/test.fixture';
import { expect, test } from '../../fixtures/test.fixture';
import { cssSelectors } from '../../constants/selectors';
import {
waitForPluginAssets,
waitForPluginSystemInit,
getCITimeoutMultiplier,
waitForPluginAssets,
waitForPluginManagementInit,
} from '../../helpers/plugin-test.helpers';
const { SIDENAV } = cssSelectors;
@ -31,11 +31,7 @@ test.describe('Enable Plugin Test', () => {
await workViewPage.waitForTaskList();
// Wait for plugin system to initialize
const pluginSystemReady = await waitForPluginSystemInit(page);
if (!pluginSystemReady) {
console.warn('[Plugin Test] Plugin system may not be fully initialized');
}
await waitForPluginManagementInit(page);
// Navigate to plugin settings
await page.click(SETTINGS_BTN);

View file

@ -1,12 +1,12 @@
import { test, expect } from '../../fixtures/test.fixture';
import { expect, test } from '../../fixtures/test.fixture';
import { cssSelectors } from '../../constants/selectors';
import {
waitForPluginAssets,
waitForPluginSystemInit,
enablePluginWithVerification,
waitForPluginInMenu,
logPluginState,
getCITimeoutMultiplier,
logPluginState,
waitForPluginAssets,
waitForPluginInMenu,
waitForPluginManagementInit,
} from '../../helpers/plugin-test.helpers';
const { SIDENAV } = cssSelectors;
@ -17,8 +17,6 @@ test.describe.serial('Plugin Enable Verify', () => {
const timeoutMultiplier = getCITimeoutMultiplier();
test.setTimeout(60000 * timeoutMultiplier);
console.log('[Plugin Test] Starting plugin enable verification test...');
// First, ensure plugin assets are available
const assetsAvailable = await waitForPluginAssets(page);
if (!assetsAvailable) {
@ -31,11 +29,7 @@ test.describe.serial('Plugin Enable Verify', () => {
await workViewPage.waitForTaskList();
// Wait for plugin system to initialize
const pluginSystemReady = await waitForPluginSystemInit(page);
if (!pluginSystemReady) {
console.warn('[Plugin Test] Plugin system may not be fully initialized');
}
await waitForPluginManagementInit(page);
// Navigate to plugin settings
await page.click(SETTINGS_BTN);
@ -101,7 +95,6 @@ test.describe.serial('Plugin Enable Verify', () => {
};
});
console.log('[Plugin Test] Plugin menu state:', menuResult);
expect(menuResult.hasPluginMenu).toBe(true);
expect(menuResult.buttonCount).toBeGreaterThan(0);
// Check if any button text contains "API Test Plugin" (handle whitespace)
@ -109,7 +102,5 @@ test.describe.serial('Plugin Enable Verify', () => {
text.includes('API Test Plugin'),
);
expect(hasApiTestPlugin).toBe(true);
console.log('[Plugin Test] Plugin enable verification test completed successfully');
});
});

View file

@ -1,12 +1,12 @@
import { test, expect } from '../../fixtures/test.fixture';
import { expect, test } from '../../fixtures/test.fixture';
import { cssSelectors } from '../../constants/selectors';
import {
waitForPluginAssets,
waitForPluginSystemInit,
enablePluginWithVerification,
waitForPluginInMenu,
logPluginState,
getCITimeoutMultiplier,
logPluginState,
waitForPluginAssets,
waitForPluginInMenu,
waitForPluginManagementInit,
} from '../../helpers/plugin-test.helpers';
const { SIDENAV } = cssSelectors;
@ -26,8 +26,6 @@ test.describe.serial('Plugin Iframe', () => {
const timeoutMultiplier = getCITimeoutMultiplier();
test.setTimeout(60000 * timeoutMultiplier);
console.log('[Plugin Test] Starting test setup...');
// First, ensure plugin assets are available
const assetsAvailable = await waitForPluginAssets(page);
if (!assetsAvailable) {
@ -40,11 +38,7 @@ test.describe.serial('Plugin Iframe', () => {
await workViewPage.waitForTaskList();
// Wait for plugin system to initialize
const pluginSystemReady = await waitForPluginSystemInit(page);
if (!pluginSystemReady) {
console.warn('[Plugin Test] Plugin system may not be fully initialized');
}
await waitForPluginManagementInit(page);
// Navigate to settings
const settingsBtn = page.locator(SETTINGS_BTN);
@ -117,8 +111,6 @@ test.describe.serial('Plugin Iframe', () => {
await tourDialog.waitFor({ state: 'hidden' });
}
}
console.log('[Plugin Test] Setup completed successfully');
});
test('open plugin iframe view', async ({ page }) => {

View file

@ -2,7 +2,7 @@ import { test, expect } from '../../fixtures/test.fixture';
import { cssSelectors } from '../../constants/selectors';
import {
waitForPluginAssets,
waitForPluginSystemInit,
waitForPluginManagementInit,
getCITimeoutMultiplier,
} from '../../helpers/plugin-test.helpers';
@ -18,8 +18,6 @@ test.describe('Plugin Lifecycle', () => {
const timeoutMultiplier = getCITimeoutMultiplier();
test.setTimeout(60000 * timeoutMultiplier);
console.log('[Plugin Test] Starting plugin lifecycle test setup...');
// First, ensure plugin assets are available
const assetsAvailable = await waitForPluginAssets(page);
if (!assetsAvailable) {
@ -32,25 +30,21 @@ test.describe('Plugin Lifecycle', () => {
await workViewPage.waitForTaskList();
// Wait for plugin system to initialize
const pluginSystemReady = await waitForPluginSystemInit(page);
if (!pluginSystemReady) {
console.warn('[Plugin Test] Plugin system may not be fully initialized');
}
await waitForPluginManagementInit(page);
// Enable API Test Plugin
const settingsBtn = page.locator(SETTINGS_BTN);
await settingsBtn.waitFor({ state: 'visible' });
await settingsBtn.click();
await page.waitForLoadState('networkidle');
// Wait for settings page to be fully visible
await page.locator('.page-settings').waitFor({ state: 'visible' });
// Wait for navigation to settings page
await page.waitForTimeout(500); // Give time for navigation
// Wait for settings page to be fully visible - use first() to avoid multiple matches
await page.locator('.page-settings').first().waitFor({ state: 'visible' });
await page.waitForTimeout(50); // Small delay for UI settling
await page.evaluate(() => {
const configPage = document.querySelector('.page-settings');
if (!configPage) {
console.error('Not on config page');
return;
}
@ -104,7 +98,6 @@ test.describe('Plugin Lifecycle', () => {
return { found: false };
}, 'API Test Plugin');
console.log(`Plugin "API Test Plugin" enable state:`, enableResult);
expect(enableResult.found).toBe(true);
// Wait for plugin to initialize
@ -112,8 +105,8 @@ test.describe('Plugin Lifecycle', () => {
// Go back to work view
await page.goto('/#/tag/TODAY');
await page.waitForLoadState('networkidle');
// Wait for work view to be ready
// Wait for navigation and work view to be ready
await page.waitForTimeout(500); // Give time for navigation
await page.locator('.route-wrapper').waitFor({ state: 'visible' });
await page.waitForTimeout(50); // Small delay for UI settling
@ -138,8 +131,8 @@ test.describe('Plugin Lifecycle', () => {
// Click on the plugin menu item to navigate to plugin
await expect(page.locator(PLUGIN_MENU_ITEM)).toBeVisible();
await page.click(PLUGIN_MENU_ITEM);
// Wait for navigation to complete
await page.waitForLoadState('networkidle');
// Wait for navigation to plugin page
await page.waitForTimeout(500); // Give time for navigation
await page.waitForTimeout(50); // Small delay for UI settling
// Verify we navigated to the plugin page
@ -155,8 +148,10 @@ test.describe('Plugin Lifecycle', () => {
// Navigate to settings
await page.click(SETTINGS_BTN);
await page.waitForLoadState('networkidle');
await page.locator('.page-settings').waitFor({ state: 'visible' });
// Wait for navigation to settings page
await page.waitForTimeout(500); // Give time for navigation
// Wait for settings page to be visible - use first() to avoid multiple matches
await page.locator('.page-settings').first().waitFor({ state: 'visible' });
await page.waitForTimeout(200); // Small delay for UI settling
// Expand plugin section
@ -203,8 +198,6 @@ test.describe('Plugin Lifecycle', () => {
return { found: false };
}, 'API Test Plugin');
console.log('Plugin state before disable:', currentState);
// If we just enabled it, wait for it to be enabled
if (currentState.clicked) {
await page.waitForFunction(
@ -228,7 +221,7 @@ test.describe('Plugin Lifecycle', () => {
}
// Now disable the plugin
const disableResult = await page.evaluate((pluginName: string) => {
await page.evaluate((pluginName: string) => {
const cards = Array.from(document.querySelectorAll('plugin-management mat-card'));
const targetCard = cards.find((card) => {
const title = card.querySelector('mat-card-title')?.textContent || '';
@ -248,8 +241,6 @@ test.describe('Plugin Lifecycle', () => {
return { found: false };
}, 'API Test Plugin');
console.log('Disable result:', disableResult);
// Wait for toggle state to update to disabled
await page.waitForFunction(
(name) => {
@ -270,7 +261,8 @@ test.describe('Plugin Lifecycle', () => {
// Go back to work view
await page.goto('/#/tag/TODAY');
await page.waitForLoadState('networkidle');
// Wait for navigation and work view to be ready
await page.waitForTimeout(500); // Give time for navigation
await page.locator('.route-wrapper').waitFor({ state: 'visible' });
await page.waitForTimeout(500); // Small delay for UI settling

View file

@ -2,7 +2,7 @@ import { test, expect } from '../../fixtures/test.fixture';
import { cssSelectors } from '../../constants/selectors';
import {
waitForPluginAssets,
waitForPluginSystemInit,
waitForPluginManagementInit,
getCITimeoutMultiplier,
} from '../../helpers/plugin-test.helpers';
@ -20,8 +20,6 @@ test.describe.serial('Plugin Loading', () => {
const timeoutMultiplier = getCITimeoutMultiplier();
test.setTimeout(60000 * timeoutMultiplier);
console.log('[Plugin Test] Starting full plugin loading lifecycle test...');
// First, ensure plugin assets are available
const assetsAvailable = await waitForPluginAssets(page);
if (!assetsAvailable) {
@ -34,11 +32,7 @@ test.describe.serial('Plugin Loading', () => {
await workViewPage.waitForTaskList();
// Wait for plugin system to initialize
const pluginSystemReady = await waitForPluginSystemInit(page);
if (!pluginSystemReady) {
console.warn('[Plugin Test] Plugin system may not be fully initialized');
}
await waitForPluginManagementInit(page);
// Enable API Test Plugin first (implementing enableTestPlugin inline)
await page.click(SETTINGS_BTN);
@ -102,7 +96,6 @@ test.describe.serial('Plugin Loading', () => {
return { enabled: false, found: false };
}, 'API Test Plugin');
console.log(`Plugin "API Test Plugin" enable state:`, enableResult);
expect(enableResult.found).toBe(true);
await page.waitForTimeout(2000); // Wait for plugin to initialize
@ -124,7 +117,6 @@ test.describe.serial('Plugin Loading', () => {
};
});
console.log('Plugin cards found:', pluginCardsResult);
expect(pluginCardsResult.pluginCardsCount).toBeGreaterThanOrEqual(1);
expect(pluginCardsResult.pluginTitles).toContain('API Test Plugin');
@ -225,7 +217,7 @@ test.describe.serial('Plugin Loading', () => {
await expect(page.locator(PLUGIN_ITEM).first()).toBeVisible();
// Find the toggle for API Test Plugin and disable it
const disableResult = await page.evaluate(() => {
await page.evaluate(() => {
const cards = Array.from(document.querySelectorAll('plugin-management mat-card'));
const apiTestCard = cards.find((card) => {
const title = card.querySelector('mat-card-title')?.textContent || '';
@ -250,7 +242,6 @@ test.describe.serial('Plugin Loading', () => {
return result;
});
console.log('Disable plugin result:', disableResult);
await page.waitForTimeout(2000); // Give more time for plugin to unload
// Stay on the settings page, just wait for state to update
@ -269,7 +260,7 @@ test.describe.serial('Plugin Loading', () => {
await page.waitForTimeout(1000);
const enableResult = await page.evaluate(() => {
await page.evaluate(() => {
const cards = Array.from(document.querySelectorAll('plugin-management mat-card'));
const apiTestCard = cards.find((card) => {
const title = card.querySelector('mat-card-title')?.textContent || '';
@ -294,7 +285,6 @@ test.describe.serial('Plugin Loading', () => {
return result;
});
console.log('Re-enable plugin result:', enableResult);
await page.waitForTimeout(2000); // Give time for plugin to reload
// Navigate back to main view

View file

@ -2,7 +2,7 @@ import { test, expect } from '../../fixtures/test.fixture';
import { cssSelectors } from '../../constants/selectors';
import {
waitForPluginAssets,
waitForPluginSystemInit,
waitForPluginManagementInit,
getCITimeoutMultiplier,
} from '../../helpers/plugin-test.helpers';
@ -14,8 +14,6 @@ test.describe.serial('Plugin Structure Test', () => {
const timeoutMultiplier = getCITimeoutMultiplier();
test.setTimeout(60000 * timeoutMultiplier);
console.log('[Plugin Test] Starting plugin structure test...');
// First, ensure plugin assets are available
const assetsAvailable = await waitForPluginAssets(page);
if (!assetsAvailable) {
@ -28,11 +26,7 @@ test.describe.serial('Plugin Structure Test', () => {
await workViewPage.waitForTaskList();
// Wait for plugin system to initialize
const pluginSystemReady = await waitForPluginSystemInit(page);
if (!pluginSystemReady) {
console.warn('[Plugin Test] Plugin system may not be fully initialized');
}
await waitForPluginManagementInit(page);
// Navigate to plugin settings (implementing navigateToPluginSettings inline)
await page.click(SETTINGS_BTN);
@ -81,7 +75,7 @@ test.describe.serial('Plugin Structure Test', () => {
await expect(page.locator('plugin-management')).toBeVisible({ timeout: 5000 });
// Check plugin card structure
const result = await page.evaluate(() => {
await page.evaluate(() => {
const cards = Array.from(document.querySelectorAll('plugin-management mat-card'));
const apiTestCard = cards.find((card) => {
const title = card.querySelector('mat-card-title')?.textContent || '';
@ -124,7 +118,5 @@ test.describe.serial('Plugin Structure Test', () => {
})),
};
});
console.log('Plugin card structure:', JSON.stringify(result, null, 2));
});
});

View file

@ -23,13 +23,20 @@ describe('DropboxApi', () => {
dropboxApi = new DropboxApi('test-app-key', mockDropbox);
// Set up fetch spy once in beforeEach
fetchSpy = spyOn(window, 'fetch');
// Check if fetch is already a spy before creating a new one
if (jasmine.isSpy(window.fetch)) {
fetchSpy = window.fetch as jasmine.Spy;
fetchSpy.calls.reset();
} else {
fetchSpy = spyOn(window, 'fetch');
}
});
afterEach(() => {
// Clean up any spies
fetchSpy.and.callThrough();
// Reset the spy but don't remove it
if (fetchSpy) {
fetchSpy.calls.reset();
}
});
describe('updateAccessTokenFromRefreshTokenIfAvailable', () => {