Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -304,16 +304,14 @@ coverage
*.sw?

# Playwright
playwright-report/
ui-spa/playwright/test-results/
ui-spa/playwright/playwright-report/
ui-spa/blob-report/
ui-spa/playwright/.cache/
ui-spa/playwright-report/
ui-spa/playwright/integration-test-results.xml
ui-spa/playwright/.nyc_output
ui-spa/unit-test-results.xml
e2e/pw/test-results/
e2e/pw/playwright-report/
e2e/pw/.auth/
e2e/pw/.state/
e2e/pw/test-evidence/
Expand All @@ -334,7 +332,7 @@ nuget.config
# postman
*.postman_environment.json

# E2E Postman Tests
# E2E Tests
e2e/*/secrets.config.ps1
e2e/*/*.secrets.config.ps1
e2e/postman/*.postman_environment
Expand All @@ -344,6 +342,7 @@ e2e/postman/LCCTestEnvironment_updated.*
e2e/postman/*_updated.postman_collection.json
e2e/postman/*postman_collection_updated.json


# Environment files — keep templates tracked, ignore environment-specific
# values anywhere in the repo (e.g. e2e/pw/.env.local).
.env.*
Expand Down
86 changes: 86 additions & 0 deletions devops-pipelines/move-playwright-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
schedules:
- cron: '0 1 * * Tue-Sat'
displayName: 'Weekday 1am UTC test'
branches:
include:
- main
always: true

trigger: none

parameters:
- name: environment
type: string
default: staging
- name: agentPool
type: string
default: "LACC PreProd Pool"
- name: testFileSizeMb
type: number
default: 2048 # 2GB

jobs:
- job: runMoveTest
displayName: "Run Move Test with Playwright"
pool: ${{ parameters.agentPool }}
variables:
- group: lacc-automated-testing-${{ parameters.environment }}
- group: lacc-backend-config-${{ parameters.environment }}
- name: nodeVersion
value: "20.x"
- name: workingDir
value: "$(System.DefaultWorkingDirectory)/e2e/pw"

steps:
- task: UseNode@1
displayName: "Use Node.js"
inputs:
version: "$(nodeVersion)"

- task: Npm@1
displayName: "Install NPM Dependencies"
inputs:
command: "ci"
workingDir: "$(workingDir)"

- script: node_modules/.bin/playwright install --with-deps chromium
displayName: "Install Browsers"
workingDirectory: $(workingDir)

- script: |
npx --no-install --ignore-scripts \
playwright test egress-to-netapp-move-large-default.spec.ts
workingDirectory: $(workingDir)
displayName: "Run E2E Tests"
env:
CI: true
TEST_FILE_SIZE_MB: ${{ parameters.testFileSizeMb }}
BASE_URL: $(RedirectUrlLccUi)
CMS_LOGIN_PAGE: "$(LccApiBaseUrl)/api/tactical/login"
EGRESS_BASE_URL: $(EgressOptionsUrl)
TENANT_ID: $(TenantId)
LCC_API_CLIENT_ID: $(CallingAppValidAudience)
E2E_AD_USER: $(AadUserName)
E2E_AD_PASSWORD: $(AadUserPassword)
CMS_USERNAME: $(CmsUserName)
CMS_PASSWORD: $(CmsUserPassword)
EGRESS_SERVICE_ACCOUNT_AUTH: $(EgressServiceAccountAuth)
DEFAULT_WORKSPACE_ID: $(E2eEgressWorkspaceId)
DEFAULT_WORKSPACE_NAME: $(E2eEgressWorkspaceName)
DEFAULT_CASE_URN: $(E2eTestsCaseUrn)
DEFAULT_CASE_ID: $(E2eTestsCaseId)
LCC_API_BASE_URL: $(LccApiBaseUrl)
NETAPP_OPERATION_NAME: $(E2eNetAppFolderName)

- task: PublishTestResults@2
displayName: "Publish Test Results (JUnit)"
inputs:
testResultsFormat: JUnit
testResultsFiles: "$(workingDir)/playwright-report/e2e-test-report.xml"
publishRunAttachments: false
condition: succeededOrFailed()

- publish: "$(workingDir)/playwright-report"
artifact: "$(System.JobId)-e2e-playwright-report"
displayName: "Publish Report Artifact"
condition: succeededOrFailed()
31 changes: 26 additions & 5 deletions e2e/pw/fixtures/setup-helper-default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import {
authenticateEgress,
createFolder,
uploadFile,
getUploadedFile,
} from "../helpers/egress-api";
import { TacticalLoginPage } from "../pages/TacticalLoginPage";
import { AzureADLoginPage } from "../pages/AzureADLoginPage";
import { CaseSearchPage } from "../pages/CaseSearchPage";
import type { TestSetupResult, UploadedFile } from "../helpers/types";
import type { TestSetupResult } from "../helpers/types";

export interface DefaultSetupOptions {
fileSizeMb?: number;
Expand Down Expand Up @@ -75,7 +76,8 @@ export async function setupDefaultTestData(
console.log(
`[2/3] Ensuring subfolder ${uploadSubfolder} exists in source + destination...`
);
await createFolder(
// Capture the source folder id for Move test verification
const sourceSubfolderId = await createFolder(
config.egressBaseUrl,
egressToken,
workspaceId,
Expand All @@ -98,7 +100,7 @@ export async function setupDefaultTestData(
`[3/3] Uploading ${fileCount} test file(s) of ${fileSizeMb}MB to ${workspaceName} (${workspaceId}) at ${uploadPath}...`
);
const fileSizeBytes = fileSizeMb * 1024 * 1024;
const files: UploadedFile[] = [];
const uploadIds: string[] = [];

for (let i = 1; i <= fileCount; i++) {
const timestamp = new Date()
Expand All @@ -107,17 +109,33 @@ export async function setupDefaultTestData(
.slice(0, 19);
const fileName = `generated-${fileSizeMb}MB-${timestamp}-file${i}.txt`;
console.log(` Uploading ${fileName} (${i}/${fileCount})...`);
const file = await uploadFile(
const uploadId = await uploadFile(
config.egressBaseUrl,
egressToken,
workspaceId,
fileSizeBytes,
fileName,
uploadPath
);
files.push(file);
uploadIds.push(uploadId);
}

console.log (" Getting the uploaded file ID(s)...")
const files = await Promise.all(
uploadIds.map(uploadId =>
getUploadedFile(
config.egressBaseUrl,
egressToken,
workspaceId,
uploadId,
{
timeoutMs: Math.max(30000, fileSizeMb * 15000),
retryDelay: Math.min(10000,Math.max(2000, fileSizeMb * 5)),
}
)
)
);

console.log("=== Upload Complete ===\n");

console.log(
Expand Down Expand Up @@ -177,6 +195,9 @@ export async function setupDefaultTestData(
caseUrn,
caseId: Number.isFinite(caseIdNum) ? caseIdNum : undefined,
uploadSubfolder,
uploadPath,
sourceSubfolderId,
destinationSubfolderId,
egressToken,
};
}
25 changes: 21 additions & 4 deletions e2e/pw/fixtures/setup-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ import {
createWorkspace,
addUserToWorkspace,
uploadFile,
getUploadedFile,
} from "../helpers/egress-api";
import { getAuthTokens } from "../helpers/auth-api";
import { registerCase } from "../helpers/case-api";
import { TacticalLoginPage } from "../pages/TacticalLoginPage";
import { AzureADLoginPage } from "../pages/AzureADLoginPage";
import { CaseSearchPage } from "../pages/CaseSearchPage";
import type { TestSetupResult, UploadedFile } from "../helpers/types";
import type { TestSetupResult } from "../helpers/types";

export interface SetupOptions {
fileSizeMb?: number;
Expand Down Expand Up @@ -73,7 +74,7 @@ export async function setupTestData(
`[5/5] Uploading ${fileCount} test file(s) of ${fileSizeMb}MB each...`,
);
const fileSizeBytes = fileSizeMb * 1024 * 1024;
const files: UploadedFile[] = [];
const uploadIds: string[] = [];

for (let i = 1; i <= fileCount; i++) {
const timestamp = new Date()
Expand All @@ -82,16 +83,32 @@ export async function setupTestData(
.slice(0, 19);
const fileName = `generated-${fileSizeMb}MB-${timestamp}-file${i}.txt`;
console.log(` Uploading ${fileName} (${i}/${fileCount})...`);
const file = await uploadFile(
const uploadId = await uploadFile(
config.egressBaseUrl,
egressToken,
workspaceId,
fileSizeBytes,
fileName,
);
files.push(file);
uploadIds.push(uploadId);
}

console.log (" Getting the uploaded file ID(s)...")
const files = await Promise.all(
uploadIds.map(uploadId =>
getUploadedFile(
config.egressBaseUrl,
egressToken,
workspaceId,
uploadId,
{
timeoutMs: Math.max(30000, fileSizeMb * 15000),
retryDelay: Math.min(10000,Math.max(2000, fileSizeMb * 5)),
}
)
)
);

console.log("=== Workspace Setup Complete ===\n");

// Step 2: Get auth tokens and register a fresh case
Expand Down
4 changes: 2 additions & 2 deletions e2e/pw/fixtures/teardown-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ export async function teardownTestData(ctx: TeardownContext): Promise<void> {
));

const fileIds = ctx.files
.map((f) => f.id)
.filter((id): id is string => !!id);
.map((f) => f.fileId)
.filter((fileId): fileId is string => !!fileId);
await deleteFiles(config.egressBaseUrl, token, ctx.workspaceId, fileIds);

if (ctx.destinationSubfolderId) {
Expand Down
29 changes: 24 additions & 5 deletions e2e/pw/fixtures/test-fixtures-register-case.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import {
authenticateEgress,
createFolder,
uploadFile,
getUploadedFile,
} from "../helpers/egress-api";
import { REGISTER_CASE_NETAPP_FOLDER } from "../helpers/constants";
import type { TestSetupResult, UploadedFile } from "../helpers/types";
import type { TestSetupResult } from "../helpers/types";
import {
STATE_FILE,
type RegisterCaseSharedState,
Expand Down Expand Up @@ -90,24 +91,41 @@ export const test = base.extend<
` Uploading ${testOptions.fileCount} x ${testOptions.fileSizeMb}MB file(s) to ${uploadPath}...`
);
const fileSizeBytes = testOptions.fileSizeMb * 1024 * 1024;
const files: UploadedFile[] = [];
const uploadIds: string[] = [];

for (let i = 1; i <= testOptions.fileCount; i++) {
const timestamp = new Date()
.toISOString()
.replace(/[:.]/g, "-")
.slice(0, 19);
const fileName = `generated-${testOptions.fileSizeMb}MB-${timestamp}-file${i}.txt`;
const file = await uploadFile(
const uploadId = await uploadFile(
config.egressBaseUrl,
token,
shared.workspace.id,
fileSizeBytes,
fileName,
uploadPath
);
files.push(file);
uploadIds.push(uploadId);
}

console.log (" Getting the uploaded file ID(s)...\n")
const files = await Promise.all(
uploadIds.map(uploadId =>
getUploadedFile(
config.egressBaseUrl,
token,
shared.workspace.id,
uploadId,
{
timeoutMs: Math.max(30000, testOptions.fileSizeMb * 15000),
retryDelay: Math.min(10000,Math.max(2000, testOptions.fileSizeMb * 5)),
},
)
)
);

// Refresh the tactical + AD session per test and wait for the search
// radios to be enabled before handing control to the spec. This mirrors
// the manual flow and avoids HTTP 400 on /api/v1/case-search when
Expand All @@ -119,6 +137,7 @@ export const test = base.extend<
caseUrn: shared.caseUrn,
files,
uploadSubfolder,
caseId: shared.caseId,
});

// Per-test teardown. On failure we leave the uploaded files in the
Expand All @@ -134,7 +153,7 @@ export const test = base.extend<
netAppFolder: REGISTER_CASE_NETAPP_FOLDER,
caseId: shared.caseId,
testInfo,
egressToken: token,
egressToken: token
});
}, { timeout: 300_000 }],
});
Expand Down
Loading
Loading