mirror of
https://github.com/inventree/InvenTree.git
synced 2025-10-21 00:17:39 +00:00
* commit initial draft for supplier import * complete import wizard * allow importing only mp and sp * improved sample supplier plugin * add docs * add tests * bump api version * fix schema docu * fix issues from code review * commit unstaged changes * fix test * refactor part parameter bulk creation * try to fix test * fix tests * fix test for mysql * fix test * support multiple suppliers by a single plugin * hide import button if there is no supplier import plugin * make form submitable via enter * add pui test * try to prevent race condition * refactor api calls in pui tests * try to fix tests again? * fix tests * trigger: ci * update changelog * fix api_version * fix style * Update CHANGELOG.md Co-authored-by: Matthias Mair <code@mjmair.com> * add user docs --------- Co-authored-by: Matthias Mair <code@mjmair.com>
260 lines
8.0 KiB
TypeScript
260 lines
8.0 KiB
TypeScript
import test from 'playwright/test';
|
|
|
|
import {
|
|
clearTableFilters,
|
|
clickOnRowMenu,
|
|
loadTab,
|
|
navigate,
|
|
setTableChoiceFilter
|
|
} from './helpers.js';
|
|
import { doCachedLogin } from './login.js';
|
|
import { setPluginState, setSettingState } from './settings.js';
|
|
|
|
// Unit test for plugin settings
|
|
test('Plugins - Settings', async ({ browser }) => {
|
|
const page = await doCachedLogin(browser, {
|
|
username: 'admin',
|
|
password: 'inventree'
|
|
});
|
|
|
|
// Ensure that the SampleIntegration plugin is enabled
|
|
await setPluginState({
|
|
plugin: 'sample',
|
|
state: true
|
|
});
|
|
|
|
// Navigate and select the plugin
|
|
await navigate(page, 'settings/admin/plugin/');
|
|
await clearTableFilters(page);
|
|
await page.getByLabel('table-search-input').fill('integration');
|
|
await page.waitForTimeout(250);
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
await page
|
|
.getByRole('row', { name: 'SampleIntegrationPlugin' })
|
|
.getByRole('paragraph')
|
|
.click();
|
|
await page.getByRole('button', { name: 'Plugin Information' }).click();
|
|
await page
|
|
.getByLabel('Plugin Detail -')
|
|
.getByRole('button', { name: 'Plugin Settings' })
|
|
.waitFor();
|
|
|
|
// Edit numerical value
|
|
await page.getByLabel('edit-setting-NUMERICAL_SETTING').click();
|
|
const originalValue = await page
|
|
.getByLabel('number-field-value')
|
|
.inputValue();
|
|
|
|
await page
|
|
.getByLabel('number-field-value')
|
|
.fill(originalValue == '999' ? '1000' : '999');
|
|
await page.getByRole('button', { name: 'Submit' }).click();
|
|
|
|
// Change it back
|
|
await page.getByLabel('edit-setting-NUMERICAL_SETTING').click();
|
|
await page.getByLabel('number-field-value').fill(originalValue);
|
|
await page.getByRole('button', { name: 'Submit' }).click();
|
|
|
|
// Select supplier
|
|
await page.getByLabel('edit-setting-SELECT_COMPANY').click();
|
|
await page.getByLabel('related-field-value').fill('mouser');
|
|
await page.getByText('Mouser Electronics').click();
|
|
});
|
|
|
|
test('Plugins - User Settings', async ({ browser }) => {
|
|
const page = await doCachedLogin(browser);
|
|
|
|
// Ensure that the SampleIntegration plugin is enabled
|
|
await setPluginState({
|
|
plugin: 'sample',
|
|
state: true
|
|
});
|
|
|
|
// Navigate to user settings
|
|
await navigate(page, 'settings/user/');
|
|
await loadTab(page, 'Plugin Settings');
|
|
|
|
// User settings for the "Sample Plugin" should be visible
|
|
await page.getByRole('button', { name: 'Sample Plugin' }).click();
|
|
|
|
await page.getByText('User Setting 1').waitFor();
|
|
await page.getByText('User Setting 2').waitFor();
|
|
await page.getByText('User Setting 3').waitFor();
|
|
|
|
// Check for expected setting options
|
|
await page.getByLabel('edit-setting-USER_SETTING_3').click();
|
|
|
|
const val = await page.getByLabel('choice-field-value').inputValue();
|
|
|
|
await page.getByLabel('choice-field-value').click();
|
|
|
|
await page.getByRole('option', { name: 'Choice X' }).waitFor();
|
|
await page.getByRole('option', { name: 'Choice Y' }).waitFor();
|
|
await page.getByRole('option', { name: 'Choice Z' }).waitFor();
|
|
|
|
// Change the value of USER_SETTING_3
|
|
await page
|
|
.getByRole('option', { name: val == 'Choice X' ? 'Choice Z' : 'Choice X' })
|
|
.click();
|
|
await page.getByRole('button', { name: 'Submit' }).click();
|
|
|
|
await page.getByText('Setting USER_SETTING_3 updated successfully').waitFor();
|
|
});
|
|
|
|
// Test base plugin functionality
|
|
test('Plugins - Functionality', async ({ browser }) => {
|
|
// Navigate and select the plugin
|
|
const page = await doCachedLogin(browser, {
|
|
username: 'admin',
|
|
password: 'inventree',
|
|
url: 'settings/admin/plugin/'
|
|
});
|
|
|
|
// Filter plugins first
|
|
await clearTableFilters(page);
|
|
await setTableChoiceFilter(page, 'Sample', 'Yes');
|
|
await setTableChoiceFilter(page, 'Builtin', 'No');
|
|
|
|
// Activate the plugin
|
|
const cell = await page.getByText('Sample API Caller', { exact: true });
|
|
await clickOnRowMenu(cell);
|
|
|
|
// Activate the plugin (unless already activated)
|
|
if ((await page.getByRole('menuitem', { name: 'Deactivate' }).count()) == 0) {
|
|
await page.getByRole('menuitem', { name: 'Activate' }).click();
|
|
await page.getByRole('button', { name: 'Submit' }).click();
|
|
await page.getByText('The plugin was activated').waitFor();
|
|
await page.waitForTimeout(250);
|
|
}
|
|
|
|
// Deactivate the plugin again
|
|
await clickOnRowMenu(cell);
|
|
await page.getByRole('menuitem', { name: 'Deactivate' }).click();
|
|
await page.getByRole('button', { name: 'Submit' }).click();
|
|
await page.getByText('The plugin was deactivated').waitFor();
|
|
|
|
// Check for custom "mandatory" plugin
|
|
await clearTableFilters(page);
|
|
await setTableChoiceFilter(page, 'Mandatory', 'Yes');
|
|
await setTableChoiceFilter(page, 'Sample', 'Yes');
|
|
await setTableChoiceFilter(page, 'Builtin', 'No');
|
|
|
|
await page.getByText('1 - 1 / 1').waitFor();
|
|
await page
|
|
.getByRole('cell', { name: 'SampleLocatePlugin' })
|
|
.first()
|
|
.waitFor();
|
|
});
|
|
|
|
test('Plugins - Panels', async ({ browser }) => {
|
|
const page = await doCachedLogin(browser, {
|
|
username: 'admin',
|
|
password: 'inventree'
|
|
});
|
|
|
|
// Ensure that UI plugins are enabled
|
|
await setSettingState({
|
|
setting: 'ENABLE_PLUGINS_INTERFACE',
|
|
value: true
|
|
});
|
|
|
|
// Ensure that the SampleUI plugin is enabled
|
|
await setPluginState({
|
|
plugin: 'sampleui',
|
|
state: true
|
|
});
|
|
|
|
// Navigate to the "part" page
|
|
await navigate(page, 'part/69/');
|
|
|
|
// Ensure basic part tab is available
|
|
await loadTab(page, 'Part Details');
|
|
|
|
// Allow time for the plugin panels to load (they are loaded asynchronously)
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
// Check out each of the plugin panels
|
|
await loadTab(page, 'Broken Panel');
|
|
await page.getByText('Error occurred while loading plugin content').waitFor();
|
|
await loadTab(page, 'Dynamic Panel');
|
|
await page.getByText('Instance ID: 69');
|
|
await page
|
|
.getByText('This panel has been dynamically rendered by the plugin system')
|
|
.waitFor();
|
|
|
|
await loadTab(page, 'Part Panel');
|
|
await page.getByText('This content has been rendered by a custom plugin');
|
|
|
|
// Disable the plugin, and ensure it is no longer visible
|
|
await setPluginState({
|
|
plugin: 'sampleui',
|
|
state: false
|
|
});
|
|
});
|
|
|
|
/**
|
|
* Unit test for custom admin integration for plugins
|
|
*/
|
|
test('Plugins - Custom Admin', async ({ browser }) => {
|
|
const page = await doCachedLogin(browser, {
|
|
username: 'admin',
|
|
password: 'inventree'
|
|
});
|
|
|
|
// Ensure that the SampleUI plugin is enabled
|
|
await setPluginState({
|
|
plugin: 'sampleui',
|
|
state: true
|
|
});
|
|
|
|
// Navigate to the "admin" page
|
|
await navigate(page, 'settings/admin/plugin/');
|
|
|
|
// Open the plugin drawer, and ensure that the custom admin elements are visible
|
|
await page.getByText('SampleUI').click();
|
|
await page.getByRole('button', { name: 'Plugin Information' }).click();
|
|
await page
|
|
.getByLabel('Plugin Detail')
|
|
.getByRole('button', { name: 'Plugin Settings' })
|
|
.click();
|
|
await page.getByRole('button', { name: 'Plugin Configuration' }).click();
|
|
|
|
// Check for expected custom elements
|
|
await page
|
|
.getByRole('heading', { name: 'Custom Plugin Configuration Content' })
|
|
.waitFor();
|
|
await page.getByText('apple: banana').waitFor();
|
|
await page.getByText('foo: bar').waitFor();
|
|
await page.getByText('hello: world').waitFor();
|
|
});
|
|
|
|
test('Plugins - Locate Item', async ({ browser }) => {
|
|
const page = await doCachedLogin(browser, {
|
|
username: 'admin',
|
|
password: 'inventree'
|
|
});
|
|
|
|
// Ensure that the sample location plugin is enabled
|
|
await setPluginState({
|
|
plugin: 'samplelocate',
|
|
state: true
|
|
});
|
|
|
|
// Navigate to the "stock item" page
|
|
await navigate(page, 'stock/item/287/');
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
// "Locate" this item
|
|
await page.getByLabel('action-button-locate-item').click();
|
|
await page.getByRole('button', { name: 'Submit' }).click();
|
|
await page.getByText('Item location requested').waitFor();
|
|
|
|
// Show the location
|
|
await page.getByLabel('breadcrumb-1-factory').click();
|
|
|
|
await page.getByLabel('action-button-locate-item').click();
|
|
await page.getByRole('button', { name: 'Submit' }).click();
|
|
await page.getByText('Item location requested').waitFor();
|
|
});
|