Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { HttpErrorResponse } from '@angular/common/http'
import { ResourceSnapshot, resourceFromSnapshots, signal } from '@angular/core'
import { resourceFromSnapshots, ResourceSnapshot, signal } from '@angular/core'
import { TestBed } from '@angular/core/testing'
import { PPW_RESOURCE_ERROR_EXTRACTOR } from '../error-handling/extractor'
import { PpwResourceExecution, PpwResourceExecutionOptions } from './ppw-resource-execution'
Expand Down Expand Up @@ -203,6 +203,33 @@ describe('PpwResourceExecution state', () => {
expect(() => vi.runOnlyPendingTimers()).not.toThrow()
})

it('should resolve the promise with the resource value after a successful execution', async () => {
const { resource, snapshot } = createFakeHttpResource(idleSnapshot())
const execution = createExecution(resource)
const promise = execution.toPromise()

snapshot.set(resolvedSnapshot('result'))
TestBed.tick()

vi.runOnlyPendingTimers()

await expect(promise).resolves.toBe('result')
})

it('should reject the promise with the resource error after a failed execution', async () => {
const { resource, snapshot } = createFakeHttpResource(idleSnapshot())
const execution = createExecution(resource)
const error = new Error('Failed')
const promise = execution.toPromise()

snapshot.set(errorSnapshot(error))
TestBed.tick()

vi.runOnlyPendingTimers()

await expect(promise).rejects.toBe(error)
})

it('should not rerun success callbacks when only the exposed value changes', () => {
const { resource, snapshot } = createFakeHttpResource(idleSnapshot())
const onSuccess = vi.fn<(value: Exclude<TestResult, undefined>) => void>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,37 @@ export class PpwResourceExecution<TResult> {
this.#completionHandlers.add(handler)
}

/**
* Converts the current operation into a Promise that resolves or rejects
* based on the operation's completion state.
*
* @return {Promise<TResult>} A Promise that resolves with the result of
* the operation if successful, or rejects with the error if it fails.
*/
public toPromise(): Promise<TResult> {
// Start by instantiating a new Promise to be returned at the end, so we can capture the resolve and reject callbacks.
let resolve: (value: TResult) => void
let reject: (reason?: unknown) => void

const promise = new Promise<TResult>((res, rej) => {
resolve = res
reject = rej
})

// Register a completion handler that will be triggered when the resource state changes to resolved or error.
// This handler will be invoked with a boolean indicating whether the call was successful, allowing us to
// invoke the captured resolve or reject Promise callbacks with either the resource value or error.
this.#completionHandlers.add((hasFailed) => {
if (hasFailed) {
reject(this.error())
} else {
resolve(this.value())
}
})

return promise
}

/**
* Starts a set of optional executions and reports their aggregate result.
*
Expand Down
Loading