big update in share links
This commit is contained in:
+71
-48
@@ -2,66 +2,89 @@ import assert from "node:assert/strict";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import test from "node:test";
|
||||
|
||||
globalThis.location = { origin: "https://pad.example" };
|
||||
const origin = "https://pad.example";
|
||||
let currentUrl;
|
||||
let historyCall;
|
||||
let dispatchedEvent;
|
||||
|
||||
globalThis.CustomEvent = class CustomEvent {
|
||||
constructor(type, init = {}) {
|
||||
this.type = type;
|
||||
this.detail = init.detail;
|
||||
}
|
||||
};
|
||||
|
||||
globalThis.window = {
|
||||
location: null,
|
||||
history: {
|
||||
pushState(state, _title, url) {
|
||||
historyCall = { method: "pushState", state };
|
||||
setLocation(url);
|
||||
},
|
||||
replaceState(state, _title, url) {
|
||||
historyCall = { method: "replaceState", state };
|
||||
setLocation(url);
|
||||
},
|
||||
},
|
||||
dispatchEvent(event) {
|
||||
dispatchedEvent = event;
|
||||
},
|
||||
};
|
||||
|
||||
function setLocation(value) {
|
||||
currentUrl = new URL(value, origin);
|
||||
window.location = {
|
||||
get href() { return currentUrl.href; },
|
||||
get search() { return currentUrl.search; },
|
||||
};
|
||||
}
|
||||
|
||||
function resetWindow(value) {
|
||||
setLocation(value);
|
||||
historyCall = undefined;
|
||||
dispatchedEvent = undefined;
|
||||
}
|
||||
|
||||
const source = await readFile(new URL("../static/js/url-state.js", import.meta.url), "utf8");
|
||||
const moduleUrl = `data:text/javascript;base64,${Buffer.from(source).toString("base64")}`;
|
||||
const { editorResourceUrl, withShareToken } = await import(moduleUrl);
|
||||
const { currentShareUrl, readEditorState, writeEditorState } = await import(moduleUrl);
|
||||
|
||||
function parsed(path) {
|
||||
return new URL(path, "https://pad.example");
|
||||
}
|
||||
|
||||
test("workspace share token is preserved when opening a note", () => {
|
||||
const url = parsed(editorResourceUrl("/w/private/n/first", {
|
||||
shareToken: "share-token-123",
|
||||
view: "split",
|
||||
mode: "markdown",
|
||||
}));
|
||||
|
||||
assert.equal(url.pathname, "/w/private/n/first");
|
||||
assert.equal(url.searchParams.get("share"), "share-token-123");
|
||||
assert.equal(url.searchParams.get("view"), "split");
|
||||
assert.equal(url.searchParams.get("mode"), "markdown");
|
||||
test("editor state reads supported values", () => {
|
||||
resetWindow("/w/demo/n/note?view=preview&mode=text");
|
||||
assert.deepEqual(readEditorState(), { view: "preview", mode: "text" });
|
||||
});
|
||||
|
||||
test("share token is preserved when returning to the workspace", () => {
|
||||
const url = parsed(withShareToken("/w/private", "share-token-123"));
|
||||
|
||||
assert.equal(url.pathname, "/w/private");
|
||||
assert.equal(url.searchParams.get("share"), "share-token-123");
|
||||
test("editor state rejects unsupported values", () => {
|
||||
resetWindow("/w/demo/n/note?view=invalid&mode=html");
|
||||
assert.deepEqual(readEditorState(), { view: "split", mode: "markdown" });
|
||||
});
|
||||
|
||||
test("existing query and hash survive share-aware navigation", () => {
|
||||
const url = parsed(editorResourceUrl("/w/private/n/first?mode=text#section", {
|
||||
shareToken: "new-token",
|
||||
view: "preview",
|
||||
mode: "markdown",
|
||||
}));
|
||||
test("writing editor state preserves unrelated query and hash", () => {
|
||||
resetWindow("/w/demo/n/note?filter=recent#section");
|
||||
const result = new URL(writeEditorState({ view: "edit", mode: "text" }));
|
||||
|
||||
assert.equal(url.searchParams.get("share"), "new-token");
|
||||
assert.equal(url.searchParams.get("view"), "preview");
|
||||
assert.equal(url.searchParams.get("mode"), "markdown");
|
||||
assert.equal(url.hash, "#section");
|
||||
assert.equal(result.searchParams.get("filter"), "recent");
|
||||
assert.equal(result.searchParams.get("view"), "edit");
|
||||
assert.equal(result.searchParams.get("mode"), "text");
|
||||
assert.equal(result.hash, "#section");
|
||||
assert.equal(historyCall.method, "pushState");
|
||||
assert.deepEqual(historyCall.state, { view: "edit", mode: "text" });
|
||||
assert.equal(dispatchedEvent.type, "rustpad:urlchange");
|
||||
});
|
||||
|
||||
test("ordinary workspace navigation does not gain or retain a share token", () => {
|
||||
const url = parsed(editorResourceUrl("/w/public/n/first?share=stale-token", {
|
||||
view: "split",
|
||||
mode: "markdown",
|
||||
}));
|
||||
|
||||
assert.equal(url.searchParams.has("share"), false);
|
||||
test("replace mode uses replaceState", () => {
|
||||
resetWindow("/p/demo");
|
||||
writeEditorState({ view: "split", mode: "markdown" }, { replace: true });
|
||||
assert.equal(historyCall.method, "replaceState");
|
||||
});
|
||||
|
||||
test("current share URL adds view state without inventing access tokens", () => {
|
||||
resetWindow("/w/demo/n/note?filter=recent#section");
|
||||
const result = new URL(currentShareUrl({ view: "preview", mode: "markdown" }));
|
||||
|
||||
test("share-aware helpers reject external application URLs", () => {
|
||||
assert.equal(withShareToken("https://example.com/steal", "secret"), "/");
|
||||
});
|
||||
|
||||
|
||||
test("share-aware helpers accept same-origin absolute URLs", () => {
|
||||
const url = parsed(withShareToken("https://pad.example/w/private", "share-token-123"));
|
||||
assert.equal(url.pathname, "/w/private");
|
||||
assert.equal(url.searchParams.get("share"), "share-token-123");
|
||||
assert.equal(result.searchParams.get("filter"), "recent");
|
||||
assert.equal(result.searchParams.get("view"), "preview");
|
||||
assert.equal(result.searchParams.get("mode"), "markdown");
|
||||
assert.equal(result.searchParams.has("share"), false);
|
||||
assert.equal(result.hash, "#section");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user