diff --git a/packages/components/package-lock.json b/packages/components/package-lock.json index 4960217ef5..18780237de 100644 --- a/packages/components/package-lock.json +++ b/packages/components/package-lock.json @@ -1,12 +1,12 @@ { "name": "@labkey/components", - "version": "7.40.0", + "version": "7.41.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@labkey/components", - "version": "7.40.0", + "version": "7.41.0", "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { "@hello-pangea/dnd": "18.0.1", diff --git a/packages/components/package.json b/packages/components/package.json index 44b6b4b2c1..f4b2e6b088 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@labkey/components", - "version": "7.40.0", + "version": "7.41.0", "description": "Components, models, actions, and utility functions for LabKey applications and pages", "sideEffects": false, "files": [ diff --git a/packages/components/releaseNotes/components.md b/packages/components/releaseNotes/components.md index 4aeffd5135..0367471a67 100644 --- a/packages/components/releaseNotes/components.md +++ b/packages/components/releaseNotes/components.md @@ -1,6 +1,10 @@ # @labkey/components Components, models, actions, and utility functions for LabKey applications and pages +### version 7.41.0 +*Released*: 1 June 2026 +- GitHub Issue 903: Remove Cross-Container Sample and Data Class Import Feature + ### version 7.40.0 *Released*: 28 May 2026 - Calculated Column Assistant diff --git a/packages/components/src/internal/components/entities/models.ts b/packages/components/src/internal/components/entities/models.ts index 3df0debdf1..81ee350ee7 100644 --- a/packages/components/src/internal/components/entities/models.ts +++ b/packages/components/src/internal/components/entities/models.ts @@ -468,7 +468,6 @@ export interface EntityDataType { ancestorColumnName?: string; appUrlPrefixParts?: string[]; containerFilter?: Query.ContainerFilter; - crossFolderImportForbidden?: boolean; deleteHelpLinkTopic: string; dependencyText: Function | string; descriptionPlural: string; diff --git a/packages/test/config/integration.setup.js b/packages/test/config/integration.setup.js index f0a0bef512..8b8e2f2319 100644 --- a/packages/test/config/integration.setup.js +++ b/packages/test/config/integration.setup.js @@ -138,3 +138,11 @@ process.env.INTEGRATION_SERVER = `${protocol}://${server}:${port}`; process.env.INTEGRATION_CONTEXT_PATH = contextPath; process.env.INTEGRATION_AUTH_USER = user; process.env.INTEGRATION_AUTH_PASS = pass; + +// Seed configuration for reproducible random test data. +// Each Jest worker inherits TEST_SEED from the environment; if absent, generate +// from Date.now() and write back so utils.ts (loaded after setupFiles) sees it. +if (!process.env.TEST_SEED) { + process.env.TEST_SEED = String(Date.now() >>> 0); +} +console.log(`[LabKey Test] Random seed: ${process.env.TEST_SEED} (rerun with: TEST_SEED=${process.env.TEST_SEED})`); diff --git a/packages/test/package-lock.json b/packages/test/package-lock.json index 0e40fe84a8..d47d2db1be 100644 --- a/packages/test/package-lock.json +++ b/packages/test/package-lock.json @@ -1,12 +1,12 @@ { "name": "@labkey/test", - "version": "1.13.2", + "version": "1.14.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@labkey/test", - "version": "1.13.2", + "version": "1.14.0", "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { "properties-reader": "3.0.1", diff --git a/packages/test/package.json b/packages/test/package.json index ffb437d268..d985ecbd16 100644 --- a/packages/test/package.json +++ b/packages/test/package.json @@ -1,6 +1,6 @@ { "name": "@labkey/test", - "version": "1.13.2", + "version": "1.14.0", "description": "Configurations and utilities for JavaScript-based testing", "main": "dist/test.js", "module": "dist/test.js", diff --git a/packages/test/releaseNotes/test.md b/packages/test/releaseNotes/test.md index 97026f972c..c00217ed2e 100644 --- a/packages/test/releaseNotes/test.md +++ b/packages/test/releaseNotes/test.md @@ -1,6 +1,10 @@ # @labkey/test Utilities and configurations for running JavaScript tests with LabKey Server. +### version 1.14.0 +*Released*: 1 June 2026 +- Package updates + ### version 1.12.0 *Released*: 26 February 2026 - Package updates diff --git a/packages/test/src/ExperimentCrudUtils.ts b/packages/test/src/ExperimentCrudUtils.ts index 536b99a7c1..68512d09bf 100644 --- a/packages/test/src/ExperimentCrudUtils.ts +++ b/packages/test/src/ExperimentCrudUtils.ts @@ -111,7 +111,7 @@ export async function importData(server, importText: string, queryName: string, let errorResp = null; const response = await server.request('experiment', isSamples ? 'importSamples' : 'importData', (agent, url) => { return agent - .post(url + '?auditBehavior=DETAILED&crossFolderImport=true') + .post(url + '?auditBehavior=DETAILED') .type('form') .send({ schemaName: isSamples ? 'samples' : 'exp.data', @@ -214,7 +214,7 @@ export async function importCrossTypeData( isSamples ? 'importSamples' : 'importData', (agent, url) => { return agent - .post(url + '?auditBehavior=DETAILED&crossFolderImport=true&crossTypeImport=true') + .post(url + '?auditBehavior=DETAILED&crossTypeImport=true') .type('form') .send({ schemaName: undefined, diff --git a/packages/test/src/index.ts b/packages/test/src/index.ts index 0fdaf3822a..0dde788d50 100644 --- a/packages/test/src/index.ts +++ b/packages/test/src/index.ts @@ -11,6 +11,8 @@ import { } from './integrationUtils'; import { sleep, + random, + testSeed, shuffleArray, selectRandomN, generateDomainName, @@ -72,6 +74,8 @@ export { IntegrationTestServer, RequestOptions, sleep, + random, + testSeed, successfulResponse, TestUser, ExperimentCRUDUtils, diff --git a/packages/test/src/utils.ts b/packages/test/src/utils.ts index 6de1e3bda3..4dbaa2eb37 100644 --- a/packages/test/src/utils.ts +++ b/packages/test/src/utils.ts @@ -2,10 +2,36 @@ * Copyright (c) 2020-2026 LabKey Corporation. All rights reserved. No portion of this work may be reproduced * in any form or by any electronic or mechanical means without written permission from LabKey Corporation. */ -/** - * Utility method to asynchronously sleep for a specified number of milliseconds. - * @param ms number of milliseconds to sleep. - */ + +// Seeded PRNG (mulberry32). Reads TEST_SEED at module load time; +// falls back to Date.now() if not set. +function _mulberry32(seed: number): () => number { + return function () { + seed |= 0; + seed = seed + 0x6D2B79F5 | 0; + let t = Math.imul(seed ^ (seed >>> 15), 1 | seed); + t = t + Math.imul(t ^ (t >>> 7), 61 | t) ^ t; + return ((t ^ (t >>> 14)) >>> 0) / 4294967296; + }; +} + +const _seedStr = typeof process !== 'undefined' ? process.env?.TEST_SEED : undefined; +const _seed = _seedStr !== undefined ? (parseInt(_seedStr, 10) >>> 0) : (Date.now() >>> 0); + +/** Seeded drop-in for Math.random(). Use in tests instead of Math.random() + * so runs are reproducible via the TEST_SEED environment variable. + * + * Note: this is a module-level singleton — all test files loaded in the same Jest worker share + * one sequence. With --maxWorkers 1 (the default for integration tests) this means full + * reproducibility: the same seed always produces the same sequence regardless of which file + * calls random() and in what order. If --maxWorkers is increased, each worker gets its own + * copy of this module initialized from the same TEST_SEED, so files on different workers draw + * from independent sequences — a multi-worker run may not reproduce identically under + * --maxWorkers 1 even with the same seed. */ +export const random = _mulberry32(_seed); + +/** The seed used for this test run. Log it so failures can be reproduced with TEST_SEED=. */ +export const testSeed = _seed; const QUERY_KEY_CHARSET = '$/&}~,.'; const ALPHA = 'ABCDabcvxyz'; @@ -16,6 +42,10 @@ const WHITE_SPACE = ' \t\n\u00A0'; const FIELD_NAME_CHARSET = ALPHA + NUMERIC + QUERY_KEY_CHARSET + SPECIAL + ' '/*only space is allowed, no other whitespace chars*/; const STRING_CHARSET = ALPHA + NUMERIC + QUERY_KEY_CHARSET + SPECIAL + WHITE_SPACE; +/** + * Utility method to asynchronously sleep for a specified number of milliseconds. + * @param ms number of milliseconds to sleep. + */ export const sleep = (ms = 0): Promise => { return new Promise(resolve => { setTimeout(() => { @@ -27,7 +57,7 @@ export const sleep = (ms = 0): Promise => { export function shuffleArray(original: T[]) : T[] { const array = [...original]; for (let i = array.length - 1; i >= 0; i--) { - const j = Math.floor(Math.random() * (i + 1)); + const j = Math.floor(random() * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; } return array; @@ -45,7 +75,7 @@ export function generateRandomStr(length: number = 8, charset: string = STRING_C const charsetLength = charset.length; while (result.length < length) { - const randomIndex = Math.floor(Math.random() * charsetLength); + const randomIndex = Math.floor(random() * charsetLength); const select = charset[randomIndex]; if (!excluded || excluded.indexOf(select) === -1) result += charset[randomIndex];