chore(release): v0.8.3 version bump + changelog (#46)
* chore(release): bump 0.8.2 -> 0.8.3 Version bumped across desktop/package.json, Cargo.toml (+ only the `gridline` entry in Cargo.lock — the sqlx family is untouched), tauri.conf.json, both landing-page `const version` strings, the README's two download tables and 'current release' banners, the MAINTENANCE comment, and the version tests. Adds the 0.8.3 changelog entry and README release note covering the external client-tool resolution fix (issue #44), the MariaDB client-option fix, the four restyled tool pages, and the app-icon revert. Historical references (older changelog entries, '(v0.8.2)' feature notes) are deliberately left alone. * test(ui): scope CopyButton's unhandled-rejection capture to its own error The listener is process-global and Vitest runs several test files per worker, so an unrelated file's rejection could be recorded and fail this test. Filter the capture to the error this test creates, and stop the listener in a finally so a failing assertion cannot leak it into later tests. Verified non-vacuous: against a CopyButton without the try/catch both 'stays quiet' tests still fail with the expected assertion.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "gridline-desktop",
|
||||
"private": true,
|
||||
"version": "0.8.2",
|
||||
"version": "0.8.3",
|
||||
"description": "An open-source, high-performance database GUI client for PostgreSQL and beyond",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
Generated
+1
-1
@@ -1796,7 +1796,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gridline"
|
||||
version = "0.8.2"
|
||||
version = "0.8.3"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"chrono",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "gridline"
|
||||
version = "0.8.2"
|
||||
version = "0.8.3"
|
||||
description = "An open-source, high-performance database GUI client for PostgreSQL and beyond"
|
||||
authors = ["you"]
|
||||
edition = "2021"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "Gridline",
|
||||
"version": "0.8.2",
|
||||
"version": "0.8.3",
|
||||
"identifier": "com.adrianbonpin.gridline",
|
||||
"build": {
|
||||
"beforeDevCommand": "bun run dev",
|
||||
|
||||
@@ -15,6 +15,12 @@ function mockClipboard(writeText: (text: string) => Promise<void>) {
|
||||
* `window.unhandledrejection` for rejections originating in the environment, so
|
||||
* the process event is the only reliable signal that a failed clipboard write
|
||||
* escaped the click handler.
|
||||
*
|
||||
* `match` narrows the capture to this test's own error. It is required, not a
|
||||
* convenience: the listener is process-global, and Vitest runs several test
|
||||
* files in the same worker process — without a filter another file's rejection
|
||||
* would be recorded here and fail this test. Filtering keeps the assertion
|
||||
* precise ("did *our* rejection escape?") instead of order-dependent.
|
||||
*/
|
||||
interface UnhandledRejectionEmitter {
|
||||
on(event: "unhandledRejection", listener: (reason: unknown) => void): void;
|
||||
@@ -25,10 +31,10 @@ const nodeProcess = (
|
||||
globalThis as unknown as { process?: UnhandledRejectionEmitter }
|
||||
).process;
|
||||
|
||||
function captureUnhandledRejections() {
|
||||
function captureUnhandledRejections(match: string) {
|
||||
const seen: unknown[] = [];
|
||||
const listener = (reason: unknown) => {
|
||||
seen.push(reason);
|
||||
if (String(reason).includes(match)) seen.push(reason);
|
||||
};
|
||||
nodeProcess?.on("unhandledRejection", listener);
|
||||
return {
|
||||
@@ -96,17 +102,20 @@ describe("CopyButton", () => {
|
||||
it("stays quiet when the clipboard rejects", async () => {
|
||||
const rejected = vi.fn().mockRejectedValue(new Error("NotAllowedError"));
|
||||
mockClipboard(rejected);
|
||||
const unhandled = captureUnhandledRejections();
|
||||
const unhandled = captureUnhandledRejections("NotAllowedError");
|
||||
|
||||
render(<CopyButton text="brew install libpq" />);
|
||||
fireEvent.click(screen.getByTitle("Copy to clipboard"));
|
||||
try {
|
||||
render(<CopyButton text="brew install libpq" />);
|
||||
fireEvent.click(screen.getByTitle("Copy to clipboard"));
|
||||
|
||||
await waitFor(() => expect(rejected).toHaveBeenCalled());
|
||||
await drain();
|
||||
await waitFor(() => expect(rejected).toHaveBeenCalled());
|
||||
await drain();
|
||||
|
||||
expect(screen.getByTitle("Copy to clipboard").textContent).toBe("Copy");
|
||||
expect(unhandled.seen).toEqual([]);
|
||||
unhandled.stop();
|
||||
expect(screen.getByTitle("Copy to clipboard").textContent).toBe("Copy");
|
||||
expect(unhandled.seen).toEqual([]);
|
||||
} finally {
|
||||
unhandled.stop();
|
||||
}
|
||||
});
|
||||
|
||||
it("stays quiet when the clipboard API is unavailable", async () => {
|
||||
@@ -115,18 +124,21 @@ describe("CopyButton", () => {
|
||||
configurable: true,
|
||||
writable: true,
|
||||
});
|
||||
const unhandled = captureUnhandledRejections();
|
||||
const unhandled = captureUnhandledRejections("writeText");
|
||||
|
||||
render(<CopyButton text="brew install libpq" />);
|
||||
expect(() =>
|
||||
fireEvent.click(screen.getByTitle("Copy to clipboard")),
|
||||
).not.toThrow();
|
||||
try {
|
||||
render(<CopyButton text="brew install libpq" />);
|
||||
expect(() =>
|
||||
fireEvent.click(screen.getByTitle("Copy to clipboard")),
|
||||
).not.toThrow();
|
||||
|
||||
await drain();
|
||||
await drain();
|
||||
|
||||
expect(screen.getByTitle("Copy to clipboard").textContent).toBe("Copy");
|
||||
expect(unhandled.seen).toEqual([]);
|
||||
unhandled.stop();
|
||||
expect(screen.getByTitle("Copy to clipboard").textContent).toBe("Copy");
|
||||
expect(unhandled.seen).toEqual([]);
|
||||
} finally {
|
||||
unhandled.stop();
|
||||
}
|
||||
});
|
||||
|
||||
it("uses a custom label for the accessible name", () => {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import tauriConf from "../../src-tauri/tauri.conf.json";
|
||||
|
||||
describe("tauri bundle config (v0.8.2)", () => {
|
||||
describe("tauri bundle config (v0.8.3)", () => {
|
||||
it("declares bundled pg_tools resources", () => {
|
||||
expect(tauriConf.bundle.resources).toContain("resources/pg_tools/*");
|
||||
});
|
||||
it("version is 0.8.2", () => {
|
||||
expect(tauriConf.version).toBe("0.8.2");
|
||||
it("version is 0.8.3", () => {
|
||||
expect(tauriConf.version).toBe("0.8.3");
|
||||
});
|
||||
it("declares a .sql file association with alternate rank", () => {
|
||||
const assoc = tauriConf.bundle.fileAssociations;
|
||||
|
||||
@@ -6,7 +6,7 @@ import readme from "../../../README.md?raw";
|
||||
import landing from "../../../www/public/landing.js?raw";
|
||||
import roadmap from "../../../ROADMAP.md?raw";
|
||||
|
||||
describe("v0.8.2 docs coverage", () => {
|
||||
describe("v0.8.3 docs coverage", () => {
|
||||
it("AGENTS.md marks inline cell editing complete", () => {
|
||||
expect(agents).toContain("Inline cell editing");
|
||||
expect(agents).toMatch(/Inline cell editing \| ✅/);
|
||||
@@ -26,8 +26,8 @@ describe("v0.8.2 docs coverage", () => {
|
||||
expect(agents).toMatch(/Connection status indicator on cards \| ✅/);
|
||||
expect(agents).toMatch(/Move-to-folder bulk action \| ✅/);
|
||||
});
|
||||
it("README declares v0.8.2", () => {
|
||||
expect(readme).toContain("0.8.2");
|
||||
it("README declares v0.8.3", () => {
|
||||
expect(readme).toContain("0.8.3");
|
||||
});
|
||||
it("AGENTS.md marks schema CRUD complete", () => {
|
||||
expect(agents).toMatch(/Schema CRUD \| ✅/);
|
||||
@@ -66,13 +66,13 @@ describe("v0.8.2 docs coverage", () => {
|
||||
expect(agents).toMatch(/Cancel long-running queries \| ✅/);
|
||||
expect(agents).toMatch(/Settings export\/import \| ✅/);
|
||||
});
|
||||
it("README links to v0.8.2 assets in both download tables", () => {
|
||||
expect(readme).toContain("releases/download/v0.8.2/");
|
||||
expect(readme).toContain("Gridline_0.8.2_aarch64.dmg");
|
||||
expect(readme).toContain("Gridline-0.8.2-1.x86_64.rpm");
|
||||
it("README links to v0.8.3 assets in both download tables", () => {
|
||||
expect(readme).toContain("releases/download/v0.8.3/");
|
||||
expect(readme).toContain("Gridline_0.8.3_aarch64.dmg");
|
||||
expect(readme).toContain("Gridline-0.8.3-1.x86_64.rpm");
|
||||
});
|
||||
it("landing.js platform download links point to v0.8.2", () => {
|
||||
expect(landing).toContain('const version = "0.8.2"');
|
||||
it("landing.js platform download links point to v0.8.3", () => {
|
||||
expect(landing).toContain('const version = "0.8.3"');
|
||||
});
|
||||
it("AGENTS.md documents the native MySQL restore and the .sql association", () => {
|
||||
// These claims would actively mislead the next contributor if they were
|
||||
|
||||
@@ -2,7 +2,7 @@ import { describe, it, expect } from "vitest";
|
||||
import pkg from "../../package.json";
|
||||
|
||||
describe("version", () => {
|
||||
it("declares v0.8.2 across the app shell", () => {
|
||||
expect(pkg.version).toBe("0.8.2");
|
||||
it("declares v0.8.3 across the app shell", () => {
|
||||
expect(pkg.version).toBe("0.8.3");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user