mirror of
https://github.com/maputnik/editor.git
synced 2026-01-17 19:00:01 +00:00
## Launch Checklist <!-- Thanks for the PR! Feel free to add or remove items from the checklist. --> - [x] Briefly describe the changes in this PR. when launching maputnik with `--static /data` those files are available under e.g. `localhost:8000/static`. In this case, root relative urls are enough (e.g. requsting `/static/fonts`...). This does currently lead to a validation error: <img width="361" height="61" alt="grafik" src="https://github.com/user-attachments/assets/2be1d649-51c9-4e64-ac44-c0089b462be2" /> - [x] Include before/after visuals or gifs if this PR includes visual changes. after this change it works: <img width="338" height="68" alt="grafik" src="https://github.com/user-attachments/assets/27f23d1b-11f6-4efc-b508-2f51bf254953" /> - [x] Write tests for all new functionality. - [x] Add an entry to `CHANGELOG.md` under the `## main` section.
160 lines
5.3 KiB
TypeScript
160 lines
5.3 KiB
TypeScript
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
import { validate, ErrorType } from "./urlopen";
|
|
|
|
// Mock window.location if not in browser environment
|
|
const mockLocation = {
|
|
protocol: "http:",
|
|
hostname: "localhost",
|
|
};
|
|
|
|
Object.defineProperty(global, "window", {
|
|
value: {
|
|
location: mockLocation,
|
|
},
|
|
writable: true,
|
|
});
|
|
|
|
describe("validate", () => {
|
|
let originalProtocol: string;
|
|
|
|
beforeEach(() => {
|
|
// Save original protocol
|
|
originalProtocol = window.location.protocol;
|
|
});
|
|
|
|
afterEach(() => {
|
|
// Restore original protocol
|
|
Object.defineProperty(window.location, "protocol", {
|
|
writable: true,
|
|
value: originalProtocol,
|
|
});
|
|
});
|
|
|
|
describe("when URL is empty", () => {
|
|
it("should return ErrorType.None", () => {
|
|
expect(validate("")).toBe(ErrorType.None);
|
|
});
|
|
});
|
|
|
|
describe("when URL is root relative", () => {
|
|
it("should return ErrorType.None", () => {
|
|
expect(validate("/static/style.json")).toBe(ErrorType.None);
|
|
});
|
|
});
|
|
|
|
describe("when window.location.protocol is https:", () => {
|
|
beforeEach(() => {
|
|
Object.defineProperty(window.location, "protocol", {
|
|
writable: true,
|
|
value: "https:",
|
|
});
|
|
});
|
|
|
|
it("should return EmptyHttpsProtocol when URL has no protocol", () => {
|
|
expect(validate("example.com")).toBe(ErrorType.EmptyHttpsProtocol);
|
|
expect(validate("www.example.com/path")).toBe(ErrorType.EmptyHttpsProtocol);
|
|
});
|
|
|
|
it("should return None for valid https URLs", () => {
|
|
expect(validate("https://example.com")).toBe(ErrorType.None);
|
|
expect(validate("https://www.example.com/path")).toBe(ErrorType.None);
|
|
});
|
|
|
|
it("should return CorsError for http URLs pointing to non-local hosts", () => {
|
|
expect(validate("http://example.com")).toBe(ErrorType.CorsError);
|
|
expect(validate("http://api.example.com/endpoint")).toBe(ErrorType.CorsError);
|
|
});
|
|
|
|
it("should return None for http URLs pointing to localhost", () => {
|
|
expect(validate("http://localhost")).toBe(ErrorType.None);
|
|
expect(validate("http://localhost:3000")).toBe(ErrorType.None);
|
|
expect(validate("http://127.0.0.1")).toBe(ErrorType.None);
|
|
expect(validate("http://127.0.0.1:8080")).toBe(ErrorType.None);
|
|
expect(validate("http://127.255.255.255")).toBe(ErrorType.None);
|
|
});
|
|
|
|
it("should return None for http URLs pointing to IPv6 localhost", () => {
|
|
expect(validate("http://[::1]")).toBe(ErrorType.None);
|
|
expect(validate("http://[::1]:3000")).toBe(ErrorType.None);
|
|
});
|
|
|
|
it("should return None for other protocols", () => {
|
|
expect(validate("ftp://example.com")).toBe(ErrorType.None);
|
|
expect(validate("ws://example.com")).toBe(ErrorType.None);
|
|
expect(validate("wss://example.com")).toBe(ErrorType.None);
|
|
});
|
|
});
|
|
|
|
describe("when window.location.protocol is http:", () => {
|
|
beforeEach(() => {
|
|
Object.defineProperty(window.location, "protocol", {
|
|
writable: true,
|
|
value: "http:",
|
|
});
|
|
});
|
|
|
|
it("should return EmptyHttpOrHttpsProtocol when URL has no protocol", () => {
|
|
expect(validate("example.com")).toBe(ErrorType.EmptyHttpOrHttpsProtocol);
|
|
expect(validate("www.example.com/path")).toBe(ErrorType.EmptyHttpOrHttpsProtocol);
|
|
});
|
|
|
|
it("should return None for valid http URLs", () => {
|
|
expect(validate("http://example.com")).toBe(ErrorType.None);
|
|
expect(validate("http://www.example.com/path")).toBe(ErrorType.None);
|
|
});
|
|
|
|
it("should return None for valid https URLs", () => {
|
|
expect(validate("https://example.com")).toBe(ErrorType.None);
|
|
expect(validate("https://www.example.com/path")).toBe(ErrorType.None);
|
|
});
|
|
|
|
it("should return None for localhost URLs", () => {
|
|
expect(validate("http://localhost")).toBe(ErrorType.None);
|
|
expect(validate("http://127.0.0.1")).toBe(ErrorType.None);
|
|
});
|
|
});
|
|
|
|
describe("edge cases", () => {
|
|
it("should handle URLs with ports", () => {
|
|
Object.defineProperty(window.location, "protocol", {
|
|
writable: true,
|
|
value: "https:",
|
|
});
|
|
|
|
expect(validate("https://example.com:8443")).toBe(ErrorType.None);
|
|
expect(validate("http://example.com:8080")).toBe(ErrorType.CorsError);
|
|
expect(validate("http://localhost:3000")).toBe(ErrorType.None);
|
|
});
|
|
|
|
it("should handle URLs with paths and query strings", () => {
|
|
Object.defineProperty(window.location, "protocol", {
|
|
writable: true,
|
|
value: "https:",
|
|
});
|
|
|
|
expect(validate("https://example.com/path?query=value")).toBe(ErrorType.None);
|
|
expect(validate("http://example.com/path?query=value")).toBe(ErrorType.CorsError);
|
|
});
|
|
|
|
it("should handle malformed URLs that cannot be parsed", () => {
|
|
Object.defineProperty(window.location, "protocol", {
|
|
writable: true,
|
|
value: "https:",
|
|
});
|
|
|
|
expect(validate("not a url at all")).toBe(ErrorType.EmptyHttpsProtocol);
|
|
expect(validate("://")).toBe(ErrorType.EmptyHttpsProtocol);
|
|
});
|
|
|
|
it("should handle localhost variations case-insensitively", () => {
|
|
Object.defineProperty(window.location, "protocol", {
|
|
writable: true,
|
|
value: "https:",
|
|
});
|
|
|
|
expect(validate("http://LOCALHOST")).toBe(ErrorType.None);
|
|
expect(validate("http://LocalHost:3000")).toBe(ErrorType.None);
|
|
});
|
|
});
|
|
});
|