Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c5f7ae1
feat: refactor getBase64FullPageScreenshotsData router
wswebcreation Jun 24, 2025
2187c66
chore: update tests
wswebcreation Jun 24, 2025
08c206c
chore: refactor beforeOptions
wswebcreation Jun 25, 2025
56e72f0
feat: adjust saveWebScreen with createBeforeScreenshotOptions
wswebcreation Jun 26, 2025
e15aa01
feat: adjust saveWebElement for createBeforeScreenshotOptions
wswebcreation Jun 26, 2025
36b63e4
chore: optimise saveWebElement
wswebcreation Jun 26, 2025
6e1f9b8
chore: restructure interface
wswebcreation Jun 26, 2025
5456c99
chore: refactor afterScreenshot options
wswebcreation Jun 26, 2025
d11f055
chore: refactor for saveWebElement
wswebcreation Jun 26, 2025
889921e
chore: refactor saveFullPageScreen
wswebcreation Jun 26, 2025
9d07686
chore: refactor saveAppScreen
wswebcreation Jun 26, 2025
0deec74
chore: refactor saveAppElement
wswebcreation Jun 26, 2025
d8d5a76
chore: refactor saveWebScreen
wswebcreation Jun 27, 2025
74259dc
chore: refactor screenshot interfaces
wswebcreation Jun 27, 2025
71eb97c
chore: and the rest
wswebcreation Jun 27, 2025
7f98011
chore: use snapshots for tests
wswebcreation Jun 27, 2025
470c622
fix: fallback for elementscreeshots
wswebcreation Jul 5, 2025
ca41af1
chore: fix local desktop run
wswebcreation Jul 5, 2025
2e43ede
chore: fix some comments
wswebcreation Jul 5, 2025
2594555
chore: code optimisation
wswebcreation Jul 5, 2025
42626d5
chore: optimisations
wswebcreation Jul 5, 2025
7f14b67
chore: then also commit the afterscreenshot stuff
wswebcreation Jul 5, 2025
562f6c9
chore: refactor a CommonCheckVariables
wswebcreation Jul 5, 2025
58b3efb
chore: refactor to use buildFolderOptions
wswebcreation Jul 5, 2025
220fd6a
chore: refactor methods options
wswebcreation Jul 5, 2025
c695fba
chore: refactor checkAppElement and checkAppScreen
wswebcreation Jul 5, 2025
dc0b10b
chore: refactored images and report code
wswebcreation Jul 17, 2025
2f644e1
chore: fix linting
wswebcreation Jul 17, 2025
221976a
chore: fix build
wswebcreation Jul 17, 2025
240fe83
Chore: remove comments
wswebcreation Jul 17, 2025
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
1 change: 1 addition & 0 deletions eslint.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module.exports = [
'**/dist/*',
'**/build/*',
'**/.next/*',
'**/.vitest-ui/*',
]
},
{
Expand Down
20 changes: 19 additions & 1 deletion packages/image-comparison-core/src/base.interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,24 @@ export interface Folders {
diffFolder: string;
}

export interface FolderPaths {
/** The actual folder path where the current screenshots need to be saved */
actualFolderPath: string;
/** The baseline folder path where the baseline screenshots can be found */
baselineFolderPath: string;
/** The diff folder path where the differences are saved */
diffFolderPath: string;
}

export interface FilePaths {
/** The actual file path where the current screenshots need to be saved */
actualFilePath: string;
/** The baseline file path where the baseline screenshots can be found */
baselineFilePath: string;
/** The diff file path where the difference is saved */
diffFilePath: string;
}

export interface BaseWebScreenshotOptions {
/**
* Disable the blinking cursor
Expand Down Expand Up @@ -188,4 +206,4 @@ export interface BaseBoundingBox {
left: number;
/** The top coordinate */
top: number;
}
}
4 changes: 2 additions & 2 deletions packages/image-comparison-core/src/base.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { rmSync } from 'node:fs'
import BaseClass from './base.js'

vi.mock('node:fs', () => ({
...vi.importActual('node:fs'), // This includes the actual implementations of other 'fs' methods
rmSync: vi.fn(), // Mock implementation for rmSync
...vi.importActual('node:fs'),
rmSync: vi.fn(),
}))

describe('BaseClass', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,26 +40,19 @@ describe('drawTabbableOnCanvas', () => {
}

beforeEach(() => {
// Reset DOM
document.body.innerHTML = ''

// Mock window properties
Object.defineProperty(window, 'innerWidth', { value: 1024, configurable: true })
Object.defineProperty(window, 'innerHeight', { value: 768, configurable: true })

// Mock document properties
Object.defineProperty(document.documentElement, 'clientHeight', { value: 768, configurable: true })
Object.defineProperty(document.documentElement, 'scrollHeight', { value: 1000, configurable: true })
Object.defineProperty(document.body, 'scrollHeight', { value: 1000, configurable: true })

// Mock window.scrollTo
window.scrollTo = vi.fn()

// Mock canvas context
const mockGetContext = vi.fn().mockReturnValue(mockCanvasContext)

HTMLCanvasElement.prototype.getContext = mockGetContext

// Reset all mock functions
vi.clearAllMocks()
})

Expand All @@ -77,7 +70,6 @@ describe('drawTabbableOnCanvas', () => {
})

it('should draw lines and circles for tabbable elements', () => {
// Create some tabbable elements
const button = document.createElement('button')
button.textContent = 'Test Button'
button.tabIndex = 0
Expand All @@ -88,7 +80,6 @@ describe('drawTabbableOnCanvas', () => {
input.tabIndex = 0
document.body.appendChild(input)

// Mock getBoundingClientRect for the elements
const mockRect = {
left: 100,
top: 100,
Expand All @@ -99,11 +90,9 @@ describe('drawTabbableOnCanvas', () => {
}
Element.prototype.getBoundingClientRect = vi.fn().mockReturnValue(mockRect)

// Mock offsetParent to make elements visible
Object.defineProperty(button, 'offsetParent', { value: document.body, configurable: true })
Object.defineProperty(input, 'offsetParent', { value: document.body, configurable: true })

// Create spies for canvas context methods
const beginPathSpy = vi.spyOn(mockCanvasContext, 'beginPath')
const globalCompositeOperationSpy = vi.spyOn(mockCanvasContext, 'globalCompositeOperation', 'set')
const fillStyleSpy = vi.spyOn(mockCanvasContext, 'fillStyle', 'set')
Expand All @@ -112,27 +101,21 @@ describe('drawTabbableOnCanvas', () => {

drawTabbableOnCanvas(defaultOptions)

// Verify the sequence of operations
expect(beginPathSpy).toHaveBeenCalled()

// Check line drawing operations (happens first)
expect(globalCompositeOperationSpy).toHaveBeenNthCalledWith(1, 'destination-over')
expect(lineWidthSpy).toHaveBeenNthCalledWith(1, defaultOptions.line!.width)
expect(strokeStyleSpy).toHaveBeenNthCalledWith(1, defaultOptions.line!.color)
expect(mockCanvasContext.moveTo).toHaveBeenCalled()
expect(mockCanvasContext.lineTo).toHaveBeenCalled()
expect(mockCanvasContext.stroke).toHaveBeenCalled()

// Check circle drawing operations (happens second)
expect(globalCompositeOperationSpy).toHaveBeenNthCalledWith(2, 'source-over')
expect(fillStyleSpy).toHaveBeenNthCalledWith(1, defaultOptions.circle!.backgroundColor)
expect(lineWidthSpy).toHaveBeenNthCalledWith(2, defaultOptions.circle!.borderWidth)
expect(strokeStyleSpy).toHaveBeenNthCalledWith(2, defaultOptions.circle!.borderColor)
expect(mockCanvasContext.arc).toHaveBeenCalled()
expect(mockCanvasContext.fill).toHaveBeenCalled()
expect(mockCanvasContext.stroke).toHaveBeenCalled()

// Check number drawing operations (happens last)
expect(fillStyleSpy).toHaveBeenNthCalledWith(2, defaultOptions.circle!.fontColor)
expect(mockCanvasContext.font).toBe(`${defaultOptions.circle!.fontSize}px ${defaultOptions.circle!.fontFamily}`)
expect(mockCanvasContext.textAlign).toBe('center')
Expand All @@ -149,7 +132,6 @@ describe('drawTabbableOnCanvas', () => {
})

it('should handle hidden elements', () => {
// Create a hidden button
const button = document.createElement('button')
button.style.visibility = 'hidden'
document.body.appendChild(button)
Expand All @@ -160,7 +142,6 @@ describe('drawTabbableOnCanvas', () => {
})

it('should handle disabled elements', () => {
// Create a disabled button
const button = document.createElement('button')
button.disabled = true
document.body.appendChild(button)
Expand Down Expand Up @@ -199,17 +180,18 @@ describe('drawTabbableOnCanvas', () => {
radio1.type = 'radio'
radio1.name = 'group1'
document.body.appendChild(radio1)

const radio2 = document.createElement('input')
radio2.type = 'radio'
radio2.name = 'group1'
radio2.checked = true
document.body.appendChild(radio2)
// Make radios visible
Object.defineProperty(radio1, 'offsetParent', { value: document.body, configurable: true })
Object.defineProperty(radio2, 'offsetParent', { value: document.body, configurable: true })
// Mock getBoundingClientRect
radio2.getBoundingClientRect = vi.fn().mockReturnValue({ left: 0, top: 0, width: 10, height: 10, right: 10, bottom: 10 })

drawTabbableOnCanvas(defaultOptions)

expect(mockCanvasContext.beginPath).toHaveBeenCalled()
})

Expand Down Expand Up @@ -253,14 +235,14 @@ describe('drawTabbableOnCanvas', () => {
Object.defineProperty(document.documentElement, 'clientHeight', { value: 100, configurable: true })
Object.defineProperty(document.documentElement, 'scrollHeight', { value: 100, configurable: true })
Object.defineProperty(document.body, 'scrollHeight', { value: 200, configurable: true })
// Set window.innerHeight to match the others
Object.defineProperty(window, 'innerHeight', { value: 100, configurable: true })
// Add a tabbable element to trigger canvas drawing

const btn = document.createElement('button')
btn.tabIndex = 0
Object.defineProperty(btn, 'offsetParent', { value: document.body, configurable: true })
btn.getBoundingClientRect = vi.fn().mockReturnValue({ left: 0, top: 0, width: 10, height: 10, right: 10, bottom: 10 })
document.body.appendChild(btn)

drawTabbableOnCanvas(defaultOptions)

const canvas = document.getElementById('wic-tabbable-canvas') as HTMLCanvasElement
Expand All @@ -272,52 +254,54 @@ describe('drawTabbableOnCanvas', () => {
Object.defineProperty(document.documentElement, 'clientHeight', { value: 100, configurable: true })
Object.defineProperty(document.documentElement, 'scrollHeight', { value: 100, configurable: true })
Object.defineProperty(document.body, 'scrollHeight', { value: 100, configurable: true })
// Add a tall div

const tallDiv = document.createElement('div')
tallDiv.style.height = '300px'
document.body.appendChild(tallDiv)
tallDiv.getBoundingClientRect = vi.fn().mockReturnValue({ top: 0 })

drawTabbableOnCanvas(defaultOptions)

const canvas = document.getElementById('wic-tabbable-canvas') as HTMLCanvasElement

expect(canvas.height).toBeGreaterThanOrEqual(100)
})

it('should not throw or attempt to draw if getContext returns null (drawLine)', () => {
// Mock getContext to return null
const originalGetContext = HTMLCanvasElement.prototype.getContext
HTMLCanvasElement.prototype.getContext = vi.fn().mockReturnValue(null)
// Add two tabbable elements to trigger drawLine

const btn1 = document.createElement('button')
btn1.tabIndex = 0
Object.defineProperty(btn1, 'offsetParent', { value: document.body, configurable: true })
btn1.getBoundingClientRect = vi.fn().mockReturnValue({ left: 0, top: 0, width: 10, height: 10, right: 10, bottom: 10 })
document.body.appendChild(btn1)

const btn2 = document.createElement('button')
btn2.tabIndex = 0
Object.defineProperty(btn2, 'offsetParent', { value: document.body, configurable: true })
btn2.getBoundingClientRect = vi.fn().mockReturnValue({ left: 20, top: 20, width: 10, height: 10, right: 30, bottom: 30 })
document.body.appendChild(btn2)
// Should not throw or call any drawing methods

expect(() => drawTabbableOnCanvas(defaultOptions)).not.toThrow()
expect(mockCanvasContext.beginPath).not.toHaveBeenCalled()
// Restore

HTMLCanvasElement.prototype.getContext = originalGetContext
})

it('should not throw or attempt to draw if getContext returns null (drawCircleAndNumber)', () => {
// Mock getContext to return null
const originalGetContext = HTMLCanvasElement.prototype.getContext
HTMLCanvasElement.prototype.getContext = vi.fn().mockReturnValue(null)
// Add one tabbable element to trigger drawCircleAndNumber

const btn = document.createElement('button')
btn.tabIndex = 0
Object.defineProperty(btn, 'offsetParent', { value: document.body, configurable: true })
btn.getBoundingClientRect = vi.fn().mockReturnValue({ left: 0, top: 0, width: 10, height: 10, right: 10, bottom: 10 })
document.body.appendChild(btn)
// Should not throw or call any drawing methods

expect(() => drawTabbableOnCanvas(defaultOptions)).not.toThrow()
expect(mockCanvasContext.beginPath).not.toHaveBeenCalled()
// Restore

HTMLCanvasElement.prototype.getContext = originalGetContext
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,27 @@ import { CONFIGURABLE } from '../mocks/mocks.js'

describe('getDocumentScrollHeight', () => {
it('should return the bodyScrollHeight', () => {
// For viewPortHeight
Object.defineProperty(document.documentElement, 'clientHeight', { value: 500, ...CONFIGURABLE })
Object.defineProperty(window, 'innerHeight', { value: 500, ...CONFIGURABLE })
// For scrollHeight
Object.defineProperty(document.documentElement, 'scrollHeight', { value: 500, ...CONFIGURABLE })
// For bodyScrollHeight
Object.defineProperty(document.body, 'scrollHeight', { value: 1500, ...CONFIGURABLE })

expect(getDocumentScrollHeight()).toEqual(1500)
})

it('should return the scrollHeight', () => {
// For viewPortHeight
Object.defineProperty(document.documentElement, 'clientHeight', { value: 500, ...CONFIGURABLE })
Object.defineProperty(window, 'innerHeight', { value: 500, ...CONFIGURABLE })
// For scrollHeight
Object.defineProperty(document.documentElement, 'scrollHeight', { value: 2250, ...CONFIGURABLE })
// For bodyScrollHeight
Object.defineProperty(document.body, 'scrollHeight', { value: 1500, ...CONFIGURABLE })

expect(getDocumentScrollHeight()).toEqual(2250)
})

it('should return the height of the largest node', () => {
// For viewPortHeight
Object.defineProperty(document.documentElement, 'clientHeight', { value: 1500, ...CONFIGURABLE })
Object.defineProperty(window, 'innerHeight', { value: 1500, ...CONFIGURABLE })
// For scrollHeight
Object.defineProperty(document.documentElement, 'scrollHeight', { value: 1500, ...CONFIGURABLE })
// For bodyScrollHeight
Object.defineProperty(document.body, 'scrollHeight', { value: 1500, ...CONFIGURABLE })
document.body.innerHTML =
'<div>' + ' <span style="height: 200px;width: 50px"/>' + ' <div style="height: 500px;width: 50px" />' + '</div>'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ describe('getScreenDimensions', () => {
Object.defineProperty(window, 'outerHeight', { value: 0 })
Object.defineProperty(window, 'outerWidth', { value: 0 })
Object.defineProperty(document.documentElement, 'clientHeight', { value: 1234 })
Object.defineProperty(document.documentElement, 'clientWidth', { value: 4321 }) // @ts-ignore
Object.defineProperty(document.documentElement, 'clientWidth', { value: 4321 })
Object.defineProperty(window, 'matchMedia', {
value: vi.fn().mockImplementation(() => ({
matches: false,
Expand Down
Loading