Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Prev Previous commit
Next Next commit
test
  • Loading branch information
pascalbaljet committed Sep 23, 2025
commit f08f8d14fa51b92d49152f8f36fdc9b7286c1136
4 changes: 2 additions & 2 deletions packages/core/src/progress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export class Progress {
ProgressComponent.done()
}

public cancel(): void {
public reset(): void {
ProgressComponent.set(0)
}

Expand Down Expand Up @@ -83,7 +83,7 @@ function finish(event: GlobalEvent<'finish'>, timeout: NodeJS.Timeout): void {
if (event.detail.visit.completed) {
progressInstance.finish()
} else if (event.detail.visit.interrupted) {
progressInstance.set(0)
progressInstance.reset()
} else if (event.detail.visit.cancelled) {
progressInstance.remove()
}
Expand Down
8 changes: 4 additions & 4 deletions packages/core/src/router.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { hideProgress, revealProgress } from '.'
import { progress } from '.'
import { eventHandler } from './eventHandler'
import { fireBeforeEvent } from './events'
import { history } from './history'
Expand Down Expand Up @@ -192,10 +192,10 @@ export class Router {
const prefetched = prefetchedRequests.get(requestParams)

if (prefetched) {
revealProgress(prefetched.inFlight)
progress.reveal(prefetched.inFlight)
prefetchedRequests.use(prefetched, requestParams)
} else {
revealProgress(true)
progress.reveal(true)
requestStream.send(Request.create(requestParams, currentPage.get()))
}
}
Expand Down Expand Up @@ -259,7 +259,7 @@ export class Router {
return
}

hideProgress()
progress.hide()

this.asyncRequestStream.interruptInFlight()

Expand Down
109 changes: 109 additions & 0 deletions packages/vue3/test-app/Pages/ProgressComponent.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<script setup lang="ts">
import { progress } from '@inertiajs/vue3'
import { ref } from 'vue'

declare global {
interface Window {
progressTests: any[]
}
}

window.progressTests = []

const logs = ref<string[]>([])

const log = (...args: any[]) => {
const message = args.join(' ')
window.progressTests.push(...args)
logs.value.push(message)
}

const testStart = () => {
progress.start()
log('started')
}

const testSet25 = () => {
progress.set(0.25)
log('set 25%')
}

const testSet50 = () => {
progress.set(0.5)
log('set 50%')
}

const testSet75 = () => {
progress.set(0.75)
log('set 75%')
}

const testFinish = () => {
progress.finish()
log('finished')
}

const testReset = () => {
progress.reset()
log('reset')
}

const testRemove = () => {
progress.remove()
log('removed')
}

const testHide = () => {
progress.hide()
log('hidden')
}

const testReveal = () => {
progress.reveal()
log('revealed')
}

const testIsStarted = () => {
log('isStarted:', progress.isStarted())
}

const testGetStatus = () => {
log('getStatus:', progress.getStatus())
}

const clearLogs = () => {
window.progressTests = []
logs.value = []
}
</script>

<template>
<div>
<h1>Progress API Test</h1>

<div>
<button @click="testStart">Start</button>
<button @click="testSet25">Set 25%</button>
<button @click="testSet50">Set 50%</button>
<button @click="testSet75">Set 75%</button>
<button @click="testFinish">Finish</button>
</div>

<div>
<button @click="testReset">Reset</button>
<button @click="testRemove">Remove</button>
<button @click="testHide">Hide</button>
<button @click="testReveal">Reveal</button>
</div>

<div>
<button @click="testIsStarted">Is Started</button>
<button @click="testGetStatus">Get Status</button>
<button @click="clearLogs">Clear</button>
</div>

<div>
Logs: <span id="logs">{{ logs.join(', ') }}</span>
</div>
</div>
</template>
2 changes: 2 additions & 0 deletions tests/app/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,8 @@ app.get('/progress/:pageNumber', (req, res) => {
)
})

app.get('/progress-component', (req, res) => inertia.render(req, res, { component: 'ProgressComponent' }))

app.get('/merge-props', (req, res) => {
inertia.render(req, res, {
component: 'MergeProps',
Expand Down
162 changes: 162 additions & 0 deletions tests/progress-component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import { expect, Locator, test } from '@playwright/test'

const getProgressPercent = async (bar: Locator) => {
return await bar.evaluate((element) => {
// Get the inline style transform value which has the original percentage
const inlineTransform = element.style.transform

if (!inlineTransform || inlineTransform === 'none') {
return 0
}

// Extract percentage from translate3d(-75%, 0px, 0px)
const match = inlineTransform.match(/translate3d\((-?\d+(?:\.\d+)?)%/)
return match ? parseFloat(match[1]) : 0
})
}

test.describe('Progress Component', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/progress-component')
})

test('start() creates nprogress bar and begins auto-animation', async ({ page }) => {
await expect(page.locator('#nprogress .bar')).not.toBeVisible()

await page.getByRole('button', { name: 'Start', exact: true }).click()

const bar = page.locator('#nprogress .bar')
const peg = page.locator('#nprogress .peg')

await expect(bar).toBeVisible()
await expect(peg).toBeVisible()

const initialTransform = await getProgressPercent(bar)
await expect(initialTransform).toBeCloseTo(-92, 1)

await page.waitForTimeout(300)
const afterTrickle = await getProgressPercent(bar)

await expect(afterTrickle).toBeGreaterThan(initialTransform)
})

test('set() without start() directly updates bar position', async ({ page }) => {
await page.getByRole('button', { name: 'Set 25%' }).click()

const bar = page.locator('#nprogress .bar')
await expect(bar).toBeVisible()

const transform25 = await getProgressPercent(bar)
await expect(transform25).toBeCloseTo(-75, 1)

await page.getByRole('button', { name: 'Set 50%' }).click()
const transform50 = await getProgressPercent(bar)
await expect(transform50).toBeCloseTo(-50, 1)

await page.getByRole('button', { name: 'Set 75%' }).click()
const transform75 = await getProgressPercent(bar)
await expect(transform75).toBeCloseTo(-25, 1)
})

test('finish() animates to 100% then fades out and removes bar', async ({ page }) => {
await page.getByRole('button', { name: 'Set 25%' }).click()

const bar = page.locator('#nprogress .bar')
await expect(bar).toBeVisible()

const beforeFinish = await getProgressPercent(bar)
await expect(beforeFinish).toBeCloseTo(-75, 1)

await page.getByRole('button', { name: 'Finish' }).click()

await page.waitForTimeout(100)

const duringFinish = await getProgressPercent(bar)
await expect(duringFinish).toBeGreaterThan(-75)

await page.waitForTimeout(250)
const at100 = await getProgressPercent(bar)
await expect(at100).toBeCloseTo(0, 1)

await page.waitForTimeout(500)
await expect(bar).not.toBeVisible()
})

test('reset() resets status to 0', async ({ page }) => {
await page.getByRole('button', { name: 'Set 50%' }).click()

const bar = page.locator('#nprogress .bar')
const transform50 = await getProgressPercent(bar)
await expect(transform50).toBeCloseTo(-50, 1)

await page.getByRole('button', { name: 'Reset' }).click()

const transform0 = await getProgressPercent(bar)
await expect(transform0).toBeCloseTo(-92, 1)
})

test('remove() completes and removes nprogress bar', async ({ page }) => {
await page.getByRole('button', { name: 'Start', exact: true }).click()
await page.getByRole('button', { name: 'Set 75%' }).click()

await expect(page.locator('#nprogress .bar')).toBeVisible()

await page.getByRole('button', { name: 'Remove' }).click()

await page.waitForTimeout(500)
await expect(page.locator('#nprogress .bar')).not.toBeVisible()
})

test('hide() and reveal() control nprogress visibility', async ({ page }) => {
await page.getByRole('button', { name: 'Start', exact: true }).click()

await expect(page.locator('#nprogress .bar')).toBeVisible()

await page.getByRole('button', { name: 'Hide' }).click()

await expect(page.locator('#nprogress .bar')).not.toBeVisible()

await page.getByRole('button', { name: 'Reveal' }).click()

await expect(page.locator('#nprogress .bar')).toBeVisible()
})

test('multiple hide() calls require multiple reveal() calls', async ({ page }) => {
await page.getByRole('button', { name: 'Start', exact: true }).click()
await expect(page.locator('#nprogress .bar')).toBeVisible()

await page.getByRole('button', { name: 'Hide' }).click()
await page.getByRole('button', { name: 'Hide' }).click()
await expect(page.locator('#nprogress .bar')).not.toBeVisible()

await page.getByRole('button', { name: 'Reveal' }).click()
await expect(page.locator('#nprogress .bar')).not.toBeVisible()

await page.getByRole('button', { name: 'Reveal' }).click()
await expect(page.locator('#nprogress .bar')).toBeVisible()
})

test('isStarted() reflects actual DOM state', async ({ page }) => {
await page.getByRole('button', { name: 'Is Started' }).click()
let tests = await page.evaluate(() => (window as any).progressTests)
let isStarted = tests[tests.length - 1]
await expect(isStarted).toBe(false)
await expect(page.locator('#nprogress .bar')).not.toBeVisible()

await page.getByRole('button', { name: 'Clear' }).click()
await page.getByRole('button', { name: 'Start', exact: true }).click()
await page.getByRole('button', { name: 'Is Started' }).click()
tests = await page.evaluate(() => (window as any).progressTests)
isStarted = tests[tests.length - 1]
await expect(isStarted).toBe(true)
await expect(page.locator('#nprogress .bar')).toBeVisible()

await page.getByRole('button', { name: 'Finish' }).click()
await page.getByRole('button', { name: 'Is Started' }).click()
tests = await page.evaluate(() => (window as any).progressTests)
isStarted = tests[tests.length - 1]
await expect(isStarted).toBe(false)
await page.waitForTimeout(500)
await expect(page.locator('#nprogress .bar')).not.toBeVisible()
})
})