unsloth/studio/frontend/tests/native-drop-webview-routing.test.ts
Maheswar Kumar 5f38afbc2d
Some checks are pending
CodeQL / Languages to analyse (push) Waiting to run
CodeQL / Analyze () (push) Blocked by required conditions
Core / Resolve the unsloth_zoo revision (push) Waiting to run
Core / Core (HF=default + TRL=default) (push) Blocked by required conditions
Core / Core (HF=4.57.6 + TRL<1) (push) Blocked by required conditions
Core / Core (HF=latest + TRL=latest) (push) Blocked by required conditions
Core / Core zoo (HF=default + TRL=default) (push) Blocked by required conditions
Core / Core zoo (HF=4.57.6 + TRL<1) (push) Blocked by required conditions
Core / Core zoo (HF=latest + TRL=latest) (push) Blocked by required conditions
Core / llama.cpp build + smoke (push) Waiting to run
Cross-platform parity / parity (ubuntu-latest) (push) Waiting to run
Cross-platform parity / parity (windows-latest) (push) Waiting to run
Interrupted install recovery / select legs (push) Waiting to run
Interrupted install recovery / kill@ (push) Blocked by required conditions
Interrupted install recovery / windows kill@ (push) Blocked by required conditions
Kaggle T4 Notebook CI / gate (push) Waiting to run
Kaggle T4 Notebook CI / T4 smoke (push) Blocked by required conditions
Kaggle T4 Unsloth GPU CI / gate (push) Waiting to run
Kaggle T4 Unsloth GPU CI / Unsloth GPU smoke (push) Blocked by required conditions
Lint CI / Source lint (Python + shell + YAML + JSON + safety nets) (push) Waiting to run
Local Agent Guides CI / connection (claude, stable) (push) Waiting to run
Local Agent Guides CI / connection (codex, stable) (push) Waiting to run
Local Agent Guides CI / connection (dsh, stable) (push) Waiting to run
Local Agent Guides CI / connection (hermes, stable) (push) Waiting to run
Local Agent Guides CI / connection (openclaw, stable) (push) Waiting to run
Local Agent Guides CI / connection (opencode, stable) (push) Waiting to run
Local Agent Guides CI / connection (opencode, v2) (push) Waiting to run
Local Agent Guides CI / file-edit (claude) (push) Waiting to run
Local Agent Guides CI / file-edit (codex) (push) Waiting to run
Local Agent Guides CI / file-edit (dsh) (push) Waiting to run
Local Agent Guides CI / file-edit (hermes) (push) Waiting to run
Local Agent Guides CI / file-edit (vibe) (push) Waiting to run
Local Agent Guides CI / resume (claude) (push) Waiting to run
Local Agent Guides CI / resume (codex) (push) Waiting to run
Local Agent Guides CI / resume (opencode) (push) Waiting to run
Local Agent Guides CI / resume (pi) (push) Waiting to run
MLX CI on Mac M1 / dispatch (push) Waiting to run
Local Agent Guides CI / connection (pi, stable) (push) Waiting to run
Local Agent Guides CI / connection (vibe, stable) (push) Waiting to run
Local Agent Guides CI / file-edit (openclaw) (push) Waiting to run
Local Agent Guides CI / file-edit (opencode) (push) Waiting to run
Local Agent Guides CI / file-edit (pi) (push) Waiting to run
Local Agent Guides CI / prompt-cache (gemma-3-270m) (push) Waiting to run
Security audit / advisory audit (pip + npm + cargo) (push) Waiting to run
Security audit / pip scan-packages :: audio-torch280 (push) Waiting to run
Security audit / pip scan-packages :: audio-torch290 (push) Waiting to run
Security audit / pip scan-packages :: extras (push) Waiting to run
Security audit / pip scan-packages :: studio (push) Waiting to run
Security audit / pip scan-packages :: hf-stack (push) Waiting to run
Security audit / npm scan-packages (Unsloth frontend tarballs) (push) Waiting to run
Security audit / npm provenance + new install-script diff (push) Waiting to run
Unsloth API CI / Unsloth API & Auth Tests (push) Waiting to run
Backend CI / (Python 3.11, floor) (push) Waiting to run
Backend CI / (Python 3.13, a-k) (push) Waiting to run
Backend CI / (Python 3.13, l-r) (push) Waiting to run
Backend CI / (Python 3.13, rest) (push) Waiting to run
Backend CI / Repo tests (CPU, rest) (push) Waiting to run
Backend CI / Repo tests (CPU, studio) (push) Waiting to run
Backend CI / Repo tests (CPU, studio-install) (push) Waiting to run
Backend CI / Shell installer tests (push) Waiting to run
Unsloth export capability / capability (windows-latest) (push) Waiting to run
Frontend CI / Frontend build + bundle sanity (push) Waiting to run
Frontend CI / Frontend unit tests (Windows) (push) Waiting to run
Unsloth GGUF CI / GGUF inference smoke (API, tools, vision) (push) Waiting to run
Mac Unsloth Install Matrix CI / Install + load (macos-15) (push) Waiting to run
Mac Unsloth Install Matrix CI / Install + load (macos-26) (push) Waiting to run
Mac Unsloth Install Matrix CI / Install + load (macos-15-intel) (push) Waiting to run
Unsloth Tauri CI / Rust unit tests (macos) (push) Waiting to run
Unsloth UI CI / Chat UI Tests (extra) (push) Waiting to run
Unsloth UI CI / Chat UI Tests (chat) (push) Waiting to run
Unsloth UI CI / Loaded-models indicator (cross-browser) (push) Waiting to run
Unsloth Update CI / Unsloth Updating Tests (push) Waiting to run
Studio VAE seam guard / seam-guard (push) Waiting to run
Mac Unsloth Install Matrix CI / Install + load (macos-26-intel) (push) Waiting to run
Mac Unsloth UI + API + Update + Inference CI / Chat UI, API, Update and GGUF inference (push) Waiting to run
Unsloth Tauri CI / Tauri Linux debug build (no codesign) (push) Waiting to run
Unsloth Tauri CI / Rust unit tests (windows) (push) Waiting to run
Unsloth Update CI / Unsloth Updating Tests (macOS) (push) Waiting to run
Unsloth Update CI / Unsloth Updating Tests (Windows) (push) Waiting to run
Windows Unsloth API CI / Unsloth API & Auth Tests (push) Waiting to run
Windows Unsloth GGUF CI / GGUF inference smoke (API, tools, vision) (push) Waiting to run
Windows Unsloth GGUF CI / Unsloth install + inference without Visual Studio (push) Waiting to run
Windows Unsloth GGUF CI / real-VS detection (VS 2022) (push) Waiting to run
Windows Unsloth GGUF CI / real-VS detection + VC++ round-trip (VS 2026) (push) Waiting to run
Windows Unsloth GGUF CI / setup.ps1 units, no-VS resolve, VC++ round-trip (windows-latest) (push) Waiting to run
Windows Unsloth UI CI / Chat UI Tests (push) Waiting to run
Windows Unsloth Update CI / Unsloth Updating Tests (push) Waiting to run
studiobench CI / Selftests, lint and the single-file build (push) Waiting to run
studiobench CI / Real-path session, every action ran (push) Waiting to run
Wheel CI / Wheel build + content sanity + import smoke (push) Waiting to run
Windows Application Control CI / installer survives a denied unsloth.exe (push) Waiting to run
Windows ARM64 CI / woa (pwsh-7) (push) Waiting to run
Windows ARM64 CI / woa (windows-powershell-5.1) (push) Waiting to run
Windows No Compiler CI / the installer spawns no C# compiler (push) Waiting to run
Workflow trigger lint / workflow-trigger lint (pull_request_target / cache-poisoning) (push) Waiting to run
Workflow trigger lint / security suites (torch-dependent) (push) Waiting to run
studio: restore file drops and composer drag feedback (#13387)
* studio: restore native file drops to the main webview

* studio: attach dropped documents to the composer and reuse drag feedback

* studio: remove unused attachment badge state

* studio: tidy native drag context import and stale drop comment

Import NativeAttachmentDragContext from the native-intents barrel like its siblings, indent the new provider in ChatPage, and update the OFFICE_ATTACHMENT_EXTS doc comment, which still pointed at the removed OFFICE_DOC_EXTS.

---------

Co-authored-by: mahiatlinux <mahiatlinux@users.noreply.github.com>
Co-authored-by: Michael Han <107991372+shimmyshimmer@users.noreply.github.com>
2026-10-12 15:43:03 -07:00

101 lines
3.5 KiB
TypeScript

// SPDX-License-Identifier: AGPL-3.0-only
// Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
import assert from "node:assert/strict";
import test from "node:test";
import { mockIPC, mockWindows } from "@tauri-apps/api/mocks";
import { readSrc, readText, registerBundlerResolver } from "./helpers/kit.ts";
registerBundlerResolver();
class ElementStub {
parentElement = null;
}
const zone = new ElementStub();
Object.assign(globalThis, {
HTMLElement: ElementStub,
window: { crypto, devicePixelRatio: 1, location: { protocol: "tauri:" } },
document: { elementFromPoint: () => zone },
});
type Registration = {
event: string;
target: { kind: string; label: string };
handler: number;
};
const registrations: Registration[] = [];
mockIPC((command, args) => {
if (command === "plugin:event|listen") {
registrations.push(args as unknown as Registration);
return registrations.length;
}
if (command === "plugin:window|scale_factor") return 1;
});
mockWindows("main");
const { nativeDropTargetAt, registerNativeDropTarget } = await import(
"../src/features/native-intents/native-drop-targets.ts"
);
function emitFromWebview(label: string, event: string, payload: unknown) {
const internals = (window as unknown as {
__TAURI_INTERNALS__: { runCallback: (id: number, event: unknown) => void };
}).__TAURI_INTERNALS__;
for (const listener of registrations) {
if (
listener.event === event &&
listener.target.kind === "Webview" &&
listener.target.label === label
) {
internals.runCallback(listener.handler, { event, id: listener.handler, payload });
}
}
}
test("native targets receive main-webview drops without claiming browser-page drops", async () => {
const delivered: string[][] = [];
const hovered: boolean[] = [];
const unregister = registerNativeDropTarget(zone as unknown as HTMLElement, {
onDrop: (paths) => delivered.push(paths),
onDragOver: (over) => hovered.push(over),
});
try {
for (let i = 0; i < 100 && !nativeDropTargetAt({ x: 10, y: 10 }); i++) {
await new Promise((resolve) => setTimeout(resolve, 5));
}
assert.equal(nativeDropTargetAt({ x: 10, y: 10 }), zone);
const payload = { position: { x: 10, y: 10 }, paths: ["/tmp/probe.txt"] };
emitFromWebview("browser-test", "tauri://drag-drop", payload);
assert.deepEqual(delivered, []);
emitFromWebview("main", "tauri://drag-enter", payload);
assert.deepEqual(hovered, [true]);
emitFromWebview("main", "tauri://drag-drop", payload);
assert.deepEqual(delivered, [["/tmp/probe.txt"]]);
assert.deepEqual(hovered, [true, false]);
} finally {
unregister();
}
});
test("chat and training subscribe to the same webview event source", () => {
for (const path of [
"features/native-intents/use-native-drop.ts",
"features/studio/sections/use-dataset-uploads.ts",
]) {
const source = readSrc(path);
assert.match(source, /getCurrentWebview\(\)\.onDragDropEvent/);
assert.doesNotMatch(source, /(?:getCurrentWindow\(\)|currentWindow)\.onDragDropEvent/);
}
});
test("Rust authorizes only drops on the main webview", () => {
const main = readText("../../src-tauri/src/main.rs");
const handler = main.slice(
main.indexOf(".on_webview_event("),
main.indexOf(".on_window_event("),
);
assert.match(handler, /webview.label\(\) == "main"/);
assert.match(handler, /tauri::WebviewEvent::DragDrop\(tauri::DragDropEvent::Drop/);
assert.match(handler, /note_dropped_paths\(paths\)/);
assert.doesNotMatch(main, /tauri::WindowEvent::DragDrop/);
});