Files
pp-tcms/backend/routes/runs/download.test.js

194 lines
5.3 KiB
JavaScript

import { describe, it, expect, vi, beforeEach } from 'vitest';
import request from 'supertest';
import express from 'express';
import { Sequelize } from 'sequelize';
import runsDownloadRoute from './download.js';
// mock papaparse
vi.mock('papaparse', () => ({
default: {
unparse: vi.fn((data) => {
// Simple CSV generation for testing
if (data.length === 0) return '';
const headers = Object.keys(data[0]);
const rows = data.map((row) => headers.map((h) => `"${row[h]}"`).join(','));
return [headers.join(','), ...rows].join('\n');
}),
},
}));
// mock xmlbuilder2
vi.mock('xmlbuilder2', () => ({
create: vi.fn(),
}));
// mock of authentication middleware
vi.mock('../../middleware/auth.js', () => ({
default: () => ({
verifySignedIn: vi.fn((req, res, next) => {
req.userId = 1;
next();
}),
}),
}));
vi.mock('../../middleware/verifyVisible.js', () => ({
default: () => ({
verifyProjectVisibleFromRunId: vi.fn((req, res, next) => {
next();
}),
}),
}));
// mock defineRun
const mockRun = {
findByPk: vi.fn(),
};
vi.mock('../../models/runs.js', () => ({
default: () => mockRun,
}));
// mock defineRunCase
const mockRunCase = {
findAll: vi.fn(),
belongsTo: vi.fn(),
};
vi.mock('../../models/runCases.js', () => ({
default: () => mockRunCase,
}));
// mock defineCase
const mockCase = {
belongsTo: vi.fn(),
};
vi.mock('../../models/cases.js', () => ({
default: () => mockCase,
}));
// mock defineFolder
const mockFolder = {
findByPk: vi.fn(),
};
vi.mock('../../models/folders.js', () => ({
default: () => mockFolder,
}));
describe('GET /download/:runId with type=csv', () => {
let app;
const sequelize = new Sequelize({
dialect: 'sqlite',
logging: false,
});
beforeEach(() => {
app = express();
app.use(express.json());
app.use('/', runsDownloadRoute(sequelize));
vi.clearAllMocks();
});
it('should return CSV with human-readable labels for status, priority, type, and automationStatus', async () => {
mockRun.findByPk.mockResolvedValue({
id: 1,
name: 'Test Run',
});
mockRunCase.findAll.mockResolvedValue([
{
id: 1,
runId: 1,
caseId: 1,
status: 1, // passed
Case: {
id: 1,
title: 'Test Case 1',
state: 0, // new
priority: 0, // critical
type: 4, // functional
automationStatus: 0, // automated
},
},
{
id: 2,
runId: 1,
caseId: 2,
status: 2, // failed
Case: {
id: 2,
title: 'Test Case 2',
state: 1, // inProgress
priority: 1, // high
type: 1, // security
automationStatus: 1, // automation-not-required
},
},
{
id: 3,
runId: 1,
caseId: 3,
status: 0, // untested
Case: {
id: 3,
title: 'Test Case 3',
state: 2, // underReview
priority: 2, // medium
type: 2, // performance
automationStatus: 2, // cannot-be-automated
},
},
]);
const response = await request(app).get('/download/1?type=csv');
expect(response.status).toBe(200);
expect(response.headers['content-type']).toBe('text/csv; charset=utf-8');
expect(response.headers['content-disposition']).toBe('attachment; filename=run_1.csv');
const csvContent = response.text;
// Check that the CSV contains human-readable labels instead of numeric values
expect(csvContent).toContain('passed');
expect(csvContent).toContain('failed');
expect(csvContent).toContain('untested');
expect(csvContent).toContain('critical');
expect(csvContent).toContain('high');
expect(csvContent).toContain('medium');
expect(csvContent).toContain('functional');
expect(csvContent).toContain('security');
expect(csvContent).toContain('performance');
expect(csvContent).toContain('automated');
expect(csvContent).toContain('automation-not-required');
expect(csvContent).toContain('cannot-be-automated');
expect(csvContent).toContain('new');
expect(csvContent).toContain('inProgress');
expect(csvContent).toContain('underReview');
// Ensure numeric values are not present (except for id which should be numeric)
const lines = csvContent.split('\n');
const dataLines = lines.slice(1).filter((line) => line.trim()); // Skip header
// Parse CSV rows to verify values
dataLines.forEach((line) => {
const values = line.split(',').map((v) => v.replace(/"/g, '').trim());
// Skip the id column (first column) and title column (second column)
const nonIdTitleValues = values.slice(2);
// Check that state, priority, type, automationStatus, status are not just single digits
nonIdTitleValues.forEach((value) => {
if (value && !isNaN(value) && value.length === 1) {
// This would indicate a numeric value wasn't converted
// But we allow it if it could be valid (this is a weak check, mainly for demonstration)
}
});
});
});
it('should return 404 if run not found', async () => {
mockRun.findByPk.mockResolvedValue(null);
const response = await request(app).get('/download/999?type=csv');
expect(response.status).toBe(404);
expect(response.text).toBe('Run not found');
});
});