diff options
Diffstat (limited to 'cli')
-rw-r--r-- | cli/js/deno_unstable.ts | 3 | ||||
-rw-r--r-- | cli/js/globals.ts | 36 | ||||
-rw-r--r-- | cli/js/lib.deno.ns.d.ts | 93 | ||||
-rw-r--r-- | cli/js/lib.deno.shared_globals.d.ts | 54 | ||||
-rw-r--r-- | cli/js/lib.deno.unstable.d.ts | 114 | ||||
-rw-r--r-- | cli/js/ops/permissions.ts | 1 | ||||
-rw-r--r-- | cli/js/permissions.ts | 79 | ||||
-rw-r--r-- | cli/js/web/navigator.ts | 12 | ||||
-rw-r--r-- | cli/js/web/permissions.ts | 181 | ||||
-rw-r--r-- | cli/tests/025_hrtime.ts | 2 | ||||
-rw-r--r-- | cli/tests/057_revoke_permissions.ts | 4 | ||||
-rw-r--r-- | cli/tests/unit/permissions_test.ts | 53 | ||||
-rw-r--r-- | cli/tests/unit/test_util.ts | 2 | ||||
-rwxr-xr-x | cli/tests/unit/unit_test_runner.ts | 2 |
14 files changed, 399 insertions, 237 deletions
diff --git a/cli/js/deno_unstable.ts b/cli/js/deno_unstable.ts index 8744abba4..7d75c1c6a 100644 --- a/cli/js/deno_unstable.ts +++ b/cli/js/deno_unstable.ts @@ -19,9 +19,6 @@ export { shutdown, ShutdownMode } from "./net.ts"; export { listen, listenDatagram, connect } from "./net_unstable.ts"; export { startTls } from "./tls.ts"; export { kill } from "./ops/process.ts"; -export { permissions, Permissions } from "./permissions.ts"; -export { PermissionStatus } from "./permissions.ts"; -export type { PermissionName, PermissionState } from "./permissions.ts"; export { DiagnosticCategory } from "./diagnostics.ts"; export type { Diagnostic, diff --git a/cli/js/globals.ts b/cli/js/globals.ts index 4548c8304..da6288bd2 100644 --- a/cli/js/globals.ts +++ b/cli/js/globals.ts @@ -7,7 +7,6 @@ import * as abortSignal from "./web/abort_signal.ts"; import * as blob from "./web/blob.ts"; import * as consoleTypes from "./web/console.ts"; import * as csprng from "./ops/get_random_values.ts"; -import type * as promiseTypes from "./web/promise.ts"; import * as customEvent from "./web/custom_event.ts"; import * as domException from "./web/dom_exception.ts"; import * as domFile from "./web/dom_file.ts"; @@ -17,16 +16,19 @@ import * as eventTarget from "./web/event_target.ts"; import * as formData from "./web/form_data.ts"; import * as fetchTypes from "./web/fetch.ts"; import * as headers from "./web/headers.ts"; +import * as navigator from "./web/navigator.ts"; +import * as permissions from "./web/permissions.ts"; +import * as performanceUtil from "./web/performance.ts"; +import type * as promiseTypes from "./web/promise.ts"; +import * as queuingStrategy from "./web/streams/queuing_strategy.ts"; +import * as readableStream from "./web/streams/readable_stream.ts"; +import * as request from "./web/request.ts"; import * as textEncoding from "./web/text_encoding.ts"; import * as timers from "./web/timers.ts"; +import * as transformStream from "./web/streams/transform_stream.ts"; import * as url from "./web/url.ts"; import * as urlSearchParams from "./web/url_search_params.ts"; import * as workers from "./web/workers.ts"; -import * as performanceUtil from "./web/performance.ts"; -import * as request from "./web/request.ts"; -import * as readableStream from "./web/streams/readable_stream.ts"; -import * as transformStream from "./web/streams/transform_stream.ts"; -import * as queuingStrategy from "./web/streams/queuing_strategy.ts"; import * as writableStream from "./web/streams/writable_stream.ts"; // These imports are not exposed and therefore are fine to just import the @@ -221,24 +223,28 @@ export const windowOrWorkerGlobalScopeProperties = { queuingStrategy.ByteLengthQueuingStrategyImpl ), CountQueuingStrategy: nonEnumerable(queuingStrategy.CountQueuingStrategyImpl), - crypto: readOnly(csprng), - File: nonEnumerable(domFile.DomFileImpl), CustomEvent: nonEnumerable(customEvent.CustomEventImpl), + crypto: readOnly(csprng), DOMException: nonEnumerable(domException.DOMExceptionImpl), ErrorEvent: nonEnumerable(errorEvent.ErrorEventImpl), Event: nonEnumerable(event.EventImpl), EventTarget: nonEnumerable(eventTarget.EventTargetImpl), - URL: nonEnumerable(url.URLImpl), - URLSearchParams: nonEnumerable(urlSearchParams.URLSearchParamsImpl), - Headers: nonEnumerable(headers.HeadersImpl), + File: nonEnumerable(domFile.DomFileImpl), FormData: nonEnumerable(formData.FormDataImpl), - TextEncoder: nonEnumerable(textEncoding.TextEncoder), - TextDecoder: nonEnumerable(textEncoding.TextDecoder), + Headers: nonEnumerable(headers.HeadersImpl), + navigator: nonEnumerable(new navigator.NavigatorImpl()), + Navigator: nonEnumerable(navigator.NavigatorImpl), + performance: writable(new performanceUtil.Performance()), + Permissions: nonEnumerable(permissions.PermissionsImpl), + PermissionStatus: nonEnumerable(permissions.PermissionStatusImpl), ReadableStream: nonEnumerable(readableStream.ReadableStreamImpl), - TransformStream: nonEnumerable(transformStream.TransformStreamImpl), Request: nonEnumerable(request.Request), Response: nonEnumerable(fetchTypes.Response), - performance: writable(new performanceUtil.Performance()), + TextDecoder: nonEnumerable(textEncoding.TextDecoder), + TextEncoder: nonEnumerable(textEncoding.TextEncoder), + TransformStream: nonEnumerable(transformStream.TransformStreamImpl), + URL: nonEnumerable(url.URLImpl), + URLSearchParams: nonEnumerable(urlSearchParams.URLSearchParamsImpl), Worker: nonEnumerable(workers.WorkerImpl), WritableStream: nonEnumerable(writableStream.WritableStreamImpl), }; diff --git a/cli/js/lib.deno.ns.d.ts b/cli/js/lib.deno.ns.d.ts index 4a3417b5d..0b46a0c4d 100644 --- a/cli/js/lib.deno.ns.d.ts +++ b/cli/js/lib.deno.ns.d.ts @@ -19,6 +19,40 @@ declare interface ImportMeta { main: boolean; } +declare interface Permissions { + /** Resolves to the current status of a permission. + * + * ```ts + * const status = await navigator.permissions.query({ name: "read", path: "/etc" }); + * if (status.state === "granted") { + * data = await Deno.readFile("/etc/passwd"); + * } + * ``` + */ + query(permissionDesc: Deno.PermissionDescriptor): Promise<PermissionStatus>; + + /** Requests the permission, and resolves to the state of the permission. + * + * ```ts + * const status = await navigator.permissions.request({ name: "env" }); + * if (status.state === "granted") { + * console.log(Deno.dir("home"); + * } else { + * console.log("'env' permission is denied."); + * } + * ``` + */ + request(permissionDesc: Deno.PermissionDescriptor): Promise<PermissionStatus>; + + /** Revokes a permission, and resolves to the state of the permission. + * + * ```ts + * const status = await Deno.revoke({ name: "run" }); + * ``` + */ + revoke(permissionDesc: Deno.PermissionDescriptor): Promise<PermissionStatus>; +} + declare namespace Deno { /** A set of error constructors that are raised by Deno APIs. */ export const errors: { @@ -1897,6 +1931,65 @@ declare namespace Deno { * Requires `allow-run` permission. */ export function run<T extends RunOptions = RunOptions>(opt: T): Process<T>; + /** The name of a "powerful feature" which needs permission. + * + * See: https://w3c.github.io/permissions/#permission-registry + * + * Note that the definition of `PermissionName` in the above spec is swapped + * out for a set of Deno permissions which are not web-compatible. */ + export type PermissionName = + | "run" + | "read" + | "write" + | "net" + | "env" + | "plugin" + | "hrtime"; + + export interface RunPermissionDescriptor { + name: "run"; + } + + export interface ReadPermissionDescriptor { + name: "read"; + path?: string; + } + + export interface WritePermissionDescriptor { + name: "write"; + path?: string; + } + + export interface NetPermissionDescriptor { + name: "net"; + url?: string; + } + + export interface EnvPermissionDescriptor { + name: "env"; + } + + export interface PluginPermissionDescriptor { + name: "plugin"; + } + + export interface HrtimePermissionDescriptor { + name: "hrtime"; + } + + /** Permission descriptors which define a permission and can be queried, + * requested, or revoked. + * + * See: https://w3c.github.io/permissions/#permission-descriptor */ + export type PermissionDescriptor = + | RunPermissionDescriptor + | ReadPermissionDescriptor + | WritePermissionDescriptor + | NetPermissionDescriptor + | EnvPermissionDescriptor + | PluginPermissionDescriptor + | HrtimePermissionDescriptor; + interface InspectOptions { depth?: number; } diff --git a/cli/js/lib.deno.shared_globals.d.ts b/cli/js/lib.deno.shared_globals.d.ts index 0c32bd0ed..3492c0da1 100644 --- a/cli/js/lib.deno.shared_globals.d.ts +++ b/cli/js/lib.deno.shared_globals.d.ts @@ -1556,6 +1556,60 @@ declare const AbortSignal: { new (): AbortSignal; }; +type PermissionState = "denied" | "granted" | "prompt"; + +interface PermissionStatusEventMap { + change: Event; +} + +interface PermissionStatus extends EventTarget { + onchange: ((this: PermissionStatus, ev: Event) => any) | null; + readonly state: PermissionState; + addEventListener<K extends keyof PermissionStatusEventMap>( + type: K, + listener: (this: PermissionStatus, ev: PermissionStatusEventMap[K]) => any, + options?: boolean | AddEventListenerOptions + ): void; + addEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions + ): void; + removeEventListener<K extends keyof PermissionStatusEventMap>( + type: K, + listener: (this: PermissionStatus, ev: PermissionStatusEventMap[K]) => any, + options?: boolean | EventListenerOptions + ): void; + removeEventListener( + type: string, + listener: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions + ): void; +} + +/** Deno does not currently support any of the browser permissions, and so the + * `name` property of the global types is `undefined`. The Deno permissions + * that are supported are defined in the `lib.deno.ns.d.ts` and pull from the + * `Deno` namespace. */ +declare interface PermissionDescriptor { + name: undefined; +} + +declare interface Permissions { + query(permissionDesc: PermissionDescriptor): Promise<PermissionStatus>; +} + +declare const Permissions: { + prototype: Permissions; + new (): Permissions; +}; + +declare class Navigator { + readonly permissions: Permissions; +} + +declare const navigator: Navigator; + interface ErrorConstructor { /** See https://v8.dev/docs/stack-trace-api#stack-trace-collection-for-custom-exceptions. */ // eslint-disable-next-line @typescript-eslint/ban-types diff --git a/cli/js/lib.deno.unstable.d.ts b/cli/js/lib.deno.unstable.d.ts index cec4f7f46..f237cd4be 100644 --- a/cli/js/lib.deno.unstable.d.ts +++ b/cli/js/lib.deno.unstable.d.ts @@ -956,120 +956,6 @@ declare namespace Deno { * Requires `allow-run` permission. */ export function kill(pid: number, signo: number): void; - /** The name of a "powerful feature" which needs permission. - * - * See: https://w3c.github.io/permissions/#permission-registry - * - * Note that the definition of `PermissionName` in the above spec is swapped - * out for a set of Deno permissions which are not web-compatible. */ - export type PermissionName = - | "run" - | "read" - | "write" - | "net" - | "env" - | "plugin" - | "hrtime"; - - /** The current status of the permission. - * - * See: https://w3c.github.io/permissions/#status-of-a-permission */ - export type PermissionState = "granted" | "denied" | "prompt"; - - export interface RunPermissionDescriptor { - name: "run"; - } - - export interface ReadPermissionDescriptor { - name: "read"; - path?: string; - } - - export interface WritePermissionDescriptor { - name: "write"; - path?: string; - } - - export interface NetPermissionDescriptor { - name: "net"; - /** Optional url associated with this descriptor. - * - * If specified: must be a valid url. Expected format: <scheme>://<host_or_ip>[:port][/path] - * If the scheme is unknown, callers should specify some scheme, such as x:// na:// unknown:// - * - * See: https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml */ - url?: string; - } - - export interface EnvPermissionDescriptor { - name: "env"; - } - - export interface PluginPermissionDescriptor { - name: "plugin"; - } - - export interface HrtimePermissionDescriptor { - name: "hrtime"; - } - - /** Permission descriptors which define a permission and can be queried, - * requested, or revoked. - * - * See: https://w3c.github.io/permissions/#permission-descriptor */ - export type PermissionDescriptor = - | RunPermissionDescriptor - | ReadPermissionDescriptor - | WritePermissionDescriptor - | NetPermissionDescriptor - | EnvPermissionDescriptor - | PluginPermissionDescriptor - | HrtimePermissionDescriptor; - - export class Permissions { - /** Resolves to the current status of a permission. - * - * ```ts - * const status = await Deno.permissions.query({ name: "read", path: "/etc" }); - * if (status.state === "granted") { - * data = await Deno.readFile("/etc/passwd"); - * } - * ``` - */ - query(desc: PermissionDescriptor): Promise<PermissionStatus>; - - /** Revokes a permission, and resolves to the state of the permission. - * - * const status = await Deno.permissions.revoke({ name: "run" }); - * assert(status.state !== "granted") - */ - revoke(desc: PermissionDescriptor): Promise<PermissionStatus>; - - /** Requests the permission, and resolves to the state of the permission. - * - * ```ts - * const status = await Deno.permissions.request({ name: "env" }); - * if (status.state === "granted") { - * console.log(Deno.dir("home"); - * } else { - * console.log("'env' permission is denied."); - * } - * ``` - */ - request(desc: PermissionDescriptor): Promise<PermissionStatus>; - } - - /** **UNSTABLE**: Under consideration to move to `navigator.permissions` to - * match web API. It could look like `navigator.permissions.query({ name: Deno.symbols.read })`. - */ - export const permissions: Permissions; - - /** see: https://w3c.github.io/permissions/#permissionstatus */ - export class PermissionStatus { - state: PermissionState; - constructor(state: PermissionState); - } - /** **UNSTABLE**: New API, yet to be vetted. Additional consideration is still * necessary around the permissions required. * diff --git a/cli/js/ops/permissions.ts b/cli/js/ops/permissions.ts index 74b9ba0f0..cb1cd7402 100644 --- a/cli/js/ops/permissions.ts +++ b/cli/js/ops/permissions.ts @@ -1,7 +1,6 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. import { sendSync } from "./dispatch_json.ts"; -import type { PermissionState } from "../permissions.ts"; interface PermissionRequest { name: string; diff --git a/cli/js/permissions.ts b/cli/js/permissions.ts deleted file mode 100644 index ab0612ad4..000000000 --- a/cli/js/permissions.ts +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -import * as permissionsOps from "./ops/permissions.ts"; - -export type PermissionName = - | "read" - | "write" - | "net" - | "env" - | "run" - | "plugin" - | "hrtime"; -// NOTE: Keep in sync with cli/permissions.rs - -export type PermissionState = "granted" | "denied" | "prompt"; - -export interface RunPermissionDescriptor { - name: "run"; -} - -export interface ReadPermissionDescriptor { - name: "read"; - path?: string; -} - -export interface WritePermissionDescriptor { - name: "write"; - path?: string; -} - -export interface NetPermissionDescriptor { - name: "net"; - url?: string; -} - -export interface EnvPermissionDescriptor { - name: "env"; -} - -export interface PluginPermissionDescriptor { - name: "plugin"; -} - -export interface HrtimePermissionDescriptor { - name: "hrtime"; -} - -export type PermissionDescriptor = - | RunPermissionDescriptor - | ReadPermissionDescriptor - | WritePermissionDescriptor - | NetPermissionDescriptor - | EnvPermissionDescriptor - | PluginPermissionDescriptor - | HrtimePermissionDescriptor; - -export class PermissionStatus { - constructor(public state: PermissionState) {} - // TODO(kt3k): implement onchange handler -} - -export class Permissions { - query(desc: PermissionDescriptor): Promise<PermissionStatus> { - const state = permissionsOps.query(desc); - return Promise.resolve(new PermissionStatus(state)); - } - - revoke(desc: PermissionDescriptor): Promise<PermissionStatus> { - const state = permissionsOps.revoke(desc); - return Promise.resolve(new PermissionStatus(state)); - } - - request(desc: PermissionDescriptor): Promise<PermissionStatus> { - const state = permissionsOps.request(desc); - return Promise.resolve(new PermissionStatus(state)); - } -} - -export const permissions = new Permissions(); diff --git a/cli/js/web/navigator.ts b/cli/js/web/navigator.ts new file mode 100644 index 000000000..351c311d0 --- /dev/null +++ b/cli/js/web/navigator.ts @@ -0,0 +1,12 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + +import { PermissionsImpl as Permissions } from "./permissions.ts"; + +export class NavigatorImpl implements Navigator { + permissions = new Permissions(); +} + +Object.defineProperty(NavigatorImpl, "name", { + value: "Navigator", + configurable: true, +}); diff --git a/cli/js/web/permissions.ts b/cli/js/web/permissions.ts new file mode 100644 index 000000000..b8ddc26a7 --- /dev/null +++ b/cli/js/web/permissions.ts @@ -0,0 +1,181 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + +import * as permissionsOps from "../ops/permissions.ts"; +import { EventTargetImpl as EventTarget } from "./event_target.ts"; + +const permissionNames = [ + "read", + "write", + "net", + "env", + "run", + "plugin", + "hrtime", +] as const; + +type PermissionName = typeof permissionNames[number]; + +interface RunPermissionDescriptor { + name: "run"; +} + +interface ReadPermissionDescriptor { + name: "read"; + path?: string; +} + +interface WritePermissionDescriptor { + name: "write"; + path?: string; +} + +interface NetPermissionDescriptor { + name: "net"; + url?: string; +} + +interface EnvPermissionDescriptor { + name: "env"; +} + +interface PluginPermissionDescriptor { + name: "plugin"; +} + +interface HrtimePermissionDescriptor { + name: "hrtime"; +} + +type DenoPermissionDescriptor = + | RunPermissionDescriptor + | ReadPermissionDescriptor + | WritePermissionDescriptor + | NetPermissionDescriptor + | EnvPermissionDescriptor + | PluginPermissionDescriptor + | HrtimePermissionDescriptor; + +interface StatusCacheValue { + state: PermissionState; + status: PermissionStatusImpl; +} + +export class PermissionStatusImpl extends EventTarget + implements PermissionStatus { + #state: { state: PermissionState }; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + onchange: ((this: PermissionStatus, event: Event) => any) | null = null; + + get state(): PermissionState { + return this.#state.state; + } + + constructor(state: { state: PermissionState }) { + super(); + this.#state = state; + } + + dispatchEvent(event: Event): boolean { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let dispatched = super.dispatchEvent(event as any); + if (dispatched && this.onchange) { + this.onchange.call(this, event); + dispatched = !event.defaultPrevented; + } + return dispatched; + } + + get [Symbol.toStringTag](): string { + return "PermissionStatus"; + } +} + +/** A cache of `PermissionStatus` objects and their last known state. */ +const statusCache = new Map<string, StatusCacheValue>(); + +/** Cache the state of a descriptor and return its `PermissionStatus`. */ +function cache( + desc: DenoPermissionDescriptor, + state: PermissionState +): PermissionStatusImpl { + let key = desc.name; + if ((desc.name === "read" || desc.name === "write") && desc.path) { + key += `-${desc.path}`; + } else if (desc.name === "net" && desc.url) { + key += `-${desc.url}`; + } + if (statusCache.has(key)) { + const status = statusCache.get(key)!; + if (status.state !== state) { + status.state = state; + status.status.dispatchEvent(new Event("change", { cancelable: false })); + } + return status.status; + } + const status: { state: PermissionState; status?: PermissionStatusImpl } = { + state, + }; + status.status = new PermissionStatusImpl(status); + statusCache.set(key, status as StatusCacheValue); + return status.status; +} + +function isValidDescriptor( + desc: PermissionDescriptor | DenoPermissionDescriptor +): desc is DenoPermissionDescriptor { + return permissionNames.includes(desc.name as PermissionName); +} + +export class PermissionsImpl implements Permissions { + query( + desc: PermissionDescriptor | DenoPermissionDescriptor + ): Promise<PermissionStatus> { + if (!isValidDescriptor(desc)) { + return Promise.reject( + new TypeError( + `The provided value "${desc.name}" is not a valid permission name.` + ) + ); + } + const state = permissionsOps.query(desc); + return Promise.resolve(cache(desc, state) as PermissionStatus); + } + + revoke( + desc: PermissionDescriptor | DenoPermissionDescriptor + ): Promise<PermissionStatus> { + if (!isValidDescriptor(desc)) { + return Promise.reject( + new TypeError( + `The provided value "${desc.name}" is not a valid permission name.` + ) + ); + } + const state = permissionsOps.revoke(desc); + return Promise.resolve(cache(desc, state) as PermissionStatus); + } + + request( + desc: PermissionDescriptor | DenoPermissionDescriptor + ): Promise<PermissionStatus> { + if (!isValidDescriptor(desc)) { + return Promise.reject( + new TypeError( + `The provided value "${desc.name}" is not a valid permission name.` + ) + ); + } + const state = permissionsOps.request(desc); + return Promise.resolve(cache(desc, state) as PermissionStatus); + } +} + +Object.defineProperty(PermissionStatusImpl, "name", { + value: "PermissionStatus", + configurable: true, +}); +Object.defineProperty(PermissionsImpl, "name", { + value: "Permissions", + configurable: true, +}); diff --git a/cli/tests/025_hrtime.ts b/cli/tests/025_hrtime.ts index 9f60b7a77..fef39ffdb 100644 --- a/cli/tests/025_hrtime.ts +++ b/cli/tests/025_hrtime.ts @@ -1,5 +1,5 @@ window.onload = async (): Promise<void> => { console.log(performance.now() % 2 !== 0); - await Deno.permissions.revoke({ name: "hrtime" }); + await navigator.permissions.revoke({ name: "hrtime" }); console.log(performance.now() % 2 === 0); }; diff --git a/cli/tests/057_revoke_permissions.ts b/cli/tests/057_revoke_permissions.ts index de8deecb4..4a39112d2 100644 --- a/cli/tests/057_revoke_permissions.ts +++ b/cli/tests/057_revoke_permissions.ts @@ -18,11 +18,11 @@ export function assert(cond: unknown): asserts cond { function genFunc(grant: Deno.PermissionName): [string, () => Promise<void>] { const gen: () => Promise<void> = async function Granted(): Promise<void> { - const status0 = await Deno.permissions.query({ name: grant }); + const status0 = await navigator.permissions.query({ name: grant }); assert(status0 != null); assert(status0.state === "granted"); - const status1 = await Deno.permissions.revoke({ name: grant }); + const status1 = await navigator.permissions.revoke({ name: grant }); assert(status1 != null); assert(status1.state === "prompt"); }; diff --git a/cli/tests/unit/permissions_test.ts b/cli/tests/unit/permissions_test.ts index 7528768a1..0de6a774b 100644 --- a/cli/tests/unit/permissions_test.ts +++ b/cli/tests/unit/permissions_test.ts @@ -1,27 +1,40 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { unitTest, assert } from "./test_util.ts"; + +import { unitTest, assert, assertThrowsAsync } from "./test_util.ts"; unitTest(async function permissionInvalidName(): Promise<void> { - let thrown = false; - try { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - await Deno.permissions.query({ name: "foo" as any }); - } catch (e) { - thrown = true; - assert(e instanceof Error); - } finally { - assert(thrown); - } + await assertThrowsAsync(async () => { + // @ts-expect-error name should not accept "foo" + await navigator.permissions.query({ name: "foo" }); + }, TypeError); }); unitTest(async function permissionNetInvalidUrl(): Promise<void> { - let thrown = false; - try { - await Deno.permissions.query({ name: "net", url: ":" }); - } catch (e) { - thrown = true; - assert(e instanceof URIError); - } finally { - assert(thrown); - } + await assertThrowsAsync(async () => { + await navigator.permissions.query({ name: "net", url: ":" }); + }, URIError); +}); + +unitTest(async function permissionQueryReturnsEventTarget(): Promise<void> { + const status = await navigator.permissions.query({ name: "hrtime" }); + assert(["granted", "denied", "prompt"].includes(status.state)); + let called = false; + status.addEventListener("change", () => { + called = true; + }); + status.dispatchEvent(new Event("change")); + assert(called); + assert(status === (await navigator.permissions.query({ name: "hrtime" }))); +}); + +unitTest(async function permissionQueryForReadReturnsSameStatus() { + const status1 = await navigator.permissions.query({ + name: "read", + path: ".", + }); + const status2 = await navigator.permissions.query({ + name: "read", + path: ".", + }); + assert(status1 === status2); }); diff --git a/cli/tests/unit/test_util.ts b/cli/tests/unit/test_util.ts index 25da7a638..dd6c858d2 100644 --- a/cli/tests/unit/test_util.ts +++ b/cli/tests/unit/test_util.ts @@ -42,7 +42,7 @@ export function fmtPerms(perms: Permissions): string { } const isGranted = async (name: Deno.PermissionName): Promise<boolean> => - (await Deno.permissions.query({ name })).state === "granted"; + (await navigator.permissions.query({ name })).state === "granted"; export async function getProcessPermissions(): Promise<Permissions> { return { diff --git a/cli/tests/unit/unit_test_runner.ts b/cli/tests/unit/unit_test_runner.ts index b2e872200..c7c494278 100755 --- a/cli/tests/unit/unit_test_runner.ts +++ b/cli/tests/unit/unit_test_runner.ts @@ -49,7 +49,7 @@ async function dropWorkerPermissions( }); for (const perm of permsToDrop) { - await Deno.permissions.revoke({ name: perm }); + await navigator.permissions.revoke({ name: perm }); } } |