Repository: sveltejs/kit
Pull request #7395 (2022-10-26 09:32:46)

use locators over direct selectors
Using https://playwright.dev/docs/locators which are stricter can help us prevent flakiness, they also break loudly and gives a much nicer error message, it would also complain when there's multiple elements that match the same selector

### Please don't delete this checklist! Before submitting the PR, please make sure you do the following:
- [ ] It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it solves.
- [ ] Ideally, include a test that fails without this PR but passes with it.

### Tests
- [x] Run the tests with `pnpm test` and lint the project with `pnpm lint` and `pnpm check`

### Changesets
- [ ] If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running `pnpm changeset` and following the prompts. All changesets should be `patch` until SvelteKit 1.0


dummdidumm: The strictness is nice, but I'm not sure how it would help with flakyness, could you elaborate on that?
ignatiusmb: I couldn't seem to find where I read it first, here's a supporting [article](https://cathalmacdonnacha.com/playwright-e2e-testing-tips-and-best-practices#heading-2-use-locators-over-selectors) that I found through a quick search for now.

The docs also mention locators as the recommended/alternative way to reduce flakiness (https://playwright.dev/docs/api/class-page#page-eval-on-selector). 

Patch:
diff --git a/.changeset/eight-donkeys-allow.md b/.changeset/eight-donkeys-allow.md
new file mode 100644
index 000000000..8dc0a30ee
--- /dev/null
+++ b/.changeset/eight-donkeys-allow.md
@@ -0,0 +1,5 @@
+---
+"@sveltejs/kit": patch
+---
+
+declare function type with named syntax
diff --git a/.changeset/itchy-ants-explode.md b/.changeset/itchy-ants-explode.md
new file mode 100644
index 000000000..903ad5f83
--- /dev/null
+++ b/.changeset/itchy-ants-explode.md
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+[chore] upgrade to vite-plugin-svelte 1.1.0 and enable prebundleSvelteLibraries
diff --git a/packages/kit/package.json b/packages/kit/package.json
index fe192eec8..4e362840f 100644
--- a/packages/kit/package.json
+++ b/packages/kit/package.json
@@ -10,7 +10,7 @@
 	"homepage": "https://kit.svelte.dev",
 	"type": "module",
 	"dependencies": {
-		"@sveltejs/vite-plugin-svelte": "^1.0.5",
+		"@sveltejs/vite-plugin-svelte": "^1.1.0",
 		"@types/cookie": "^0.5.1",
 		"cookie": "^0.5.0",
 		"devalue": "^4.0.0",
diff --git a/packages/kit/src/exports/vite/index.js b/packages/kit/src/exports/vite/index.js
index 4f8b9ee42..9ca644dec 100644
--- a/packages/kit/src/exports/vite/index.js
+++ b/packages/kit/src/exports/vite/index.js
@@ -61,7 +61,7 @@ const enforced_config = {
 
 /** @return {import('vite').Plugin[]} */
 export function sveltekit() {
-	return [...svelte(), kit()];
+	return [...svelte({ prebundleSvelteLibraries: true }), kit()];
 }
 
 /**
diff --git a/packages/kit/src/runtime/client/types.d.ts b/packages/kit/src/runtime/client/types.d.ts
index 3b441ec45..0a6ae0a8f 100644
--- a/packages/kit/src/runtime/client/types.d.ts
+++ b/packages/kit/src/runtime/client/types.d.ts
@@ -14,7 +14,7 @@ export interface Client {
 	// public API, exposed via $app/navigation
 	after_navigate: typeof afterNavigate;
 	before_navigate: typeof beforeNavigate;
-	disable_scroll_handling: () => void;
+	disable_scroll_handling(): void;
 	goto: typeof goto;
 	invalidate: typeof invalidate;
 	invalidateAll: typeof invalidateAll;
@@ -23,7 +23,7 @@ export interface Client {
 	apply_action: typeof applyAction;
 
 	// private API
-	_hydrate: (opts: {
+	_hydrate(opts: {
 		status: number;
 		error: App.Error;
 		node_ids: number[];
@@ -31,8 +31,8 @@ export interface Client {
 		routeId: string | null;
 		data: Array<import('types').ServerDataNode | null>;
 		form: Record<string, any> | null;
-	}) => Promise<void>;
-	_start_router: () => void;
+	}): Promise<void>;
+	_start_router(): void;
 }
 
 export type NavigationIntent = {
diff --git a/packages/kit/types/ambient.d.ts b/packages/kit/types/ambient.d.ts
index a16e439f8..f51b42ff3 100644
--- a/packages/kit/types/ambient.d.ts
+++ b/packages/kit/types/ambient.d.ts
@@ -103,7 +103,7 @@ declare module '$app/forms' {
 		data: FormData;
 		form: HTMLFormElement;
 		controller: AbortController;
-		cancel: () => void;
+		cancel(): void;
 	}) =>
 		| void
 		| ((opts: {
@@ -114,7 +114,7 @@ declare module '$app/forms' {
 				 * Call this to get the default behavior of a form submission response.
 				 * @param options Set `reset: false` if you don't want the `<form>` values to be reset after a successful submission.
 				 */
-				update: (options?: { reset: boolean }) => Promise<void>;
+				update(options?: { reset: boolean }): Promise<void>;
 		  }) => void);
 
 	/**
@@ -144,7 +144,7 @@ declare module '$app/forms' {
 		 * If you provide a custom function with a callback and want to use the default behavior, invoke `update` in your callback.
 		 */
 		submit?: SubmitFunction<Success, Invalid>
-	): { destroy: () => void };
+	): { destroy(): void };
 
 	/**
 	 * This action updates the `form` property of the current page with the given data and updates `$page.status`.
@@ -244,7 +244,7 @@ declare module '$app/navigation' {
 	 * `beforeNavigate` must be called during a component initialization. It remains active as long as the component is mounted.
 	 */
 	export function beforeNavigate(
-		callback: (navigation: Navigation & { cancel: () => void }) => void
+		callback: (navigation: Navigation & { cancel(): void }) => void
 	): void;
 
 	/**
@@ -303,7 +303,7 @@ declare module '$app/stores' {
 	/**
 	 *  A readable store whose initial value is `false`. If [`version.pollInterval`](https://kit.svelte.dev/docs/configuration#version) is a non-zero value, SvelteKit will poll for new versions of the app and update the store value to `true` when it detects one. `updated.check()` will force an immediate check, regardless of polling.
 	 */
-	export const updated: Readable<boolean> & { check: () => boolean };
+	export const updated: Readable<boolean> & { check(): boolean };
 
 	/**
 	 * A function that returns all of the contextual stores. On the server, this must be called during component initialization.
diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts
index ed88e2cac..7c995d2c1 100644
--- a/packages/kit/types/index.d.ts
+++ b/packages/kit/types/index.d.ts
@@ -79,7 +79,7 @@ export interface Builder {
 	 */
 	createEntries(fn: (route: RouteDefinition) => AdapterEntry): Promise<void>;
 
-	generateManifest: (opts: { relativePath: string; format?: 'esm' | 'cjs' }) => string;
+	generateManifest(opts: { relativePath: string; format?: 'esm' | 'cjs' }): string;
 
 	getBuildDirectory(name: string): string;
 	getClientDirectory(): string;
@@ -118,7 +118,7 @@ export interface Builder {
 		from: string,
 		to: string,
 		opts?: {
-			filter?: (basename: string) => boolean;
+			filter?(basename: string): boolean;
 			replace?: Record<string, string>;
 		}
 	): string[];
@@ -137,8 +137,8 @@ export interface Config {
 		source?: string;
 		dir?: string;
 		emitTypes?: boolean;
-		exports?: (filepath: string) => boolean;
-		files?: (filepath: string) => boolean;
+		exports?(filepath: string): boolean;
+		files?(filepath: string): boolean;
 	};
 	preprocess?: any;
 	[key: string]: any;
@@ -225,7 +225,7 @@ export interface KitConfig {
 	};
 	serviceWorker?: {
 		register?: boolean;
-		files?: (filepath: string) => boolean;
+		files?(filepath: string): boolean;
 	};
 	trailingSlash?: TrailingSlash;
 	version?: {
@@ -311,14 +311,14 @@ export interface LoadEvent<
 	 *
 	 * `setHeaders` has no effect when a `load` function runs in the browser.
 	 */
-	setHeaders: (headers: Record<string, string>) => void;
+	setHeaders(headers: Record<string, string>): void;
 	/**
 	 * `await parent()` returns data from parent `+layout.js` `load` functions.
 	 * Implicitly, a missing `+layout.js` is treated as a `({ data }) => data` function, meaning that it will return and forward data from parent `+layout.server.js` files.
 	 *
 	 * Be careful not to introduce accidental waterfalls when using `await parent()`. If for example you only want to merge parent data into the returned output, call it _after_ fetching your other data.
 	 */
-	parent: () => Promise<ParentData>;
+	parent(): Promise<ParentData>;
 	/**
 	 * This function declares that the `load` function has a _dependency_ on one or more URLs or custom identifiers, which can subsequently be used with [`invalidate()`](/docs/modules#$app-navigation-invalidate) to cause `load` to rerun.
 	 *
@@ -356,7 +356,7 @@ export interface LoadEvent<
 	 * <button on:click={increase}>Increase Count</button>
 	 * ```
 	 */
-	depends: (...deps: string[]) => void;
+	depends(...deps: string[]): void;
 }
 
 export interface NavigationEvent<
@@ -449,7 +449,7 @@ export interface RequestEvent<
 	/**
 	 * The client's IP address, set by the adapter.
 	 */
-	getClientAddress: () => string;
+	getClientAddress(): string;
 	/**
 	 * Contains custom data that was added to the request within the [`handle hook`](https://kit.svelte.dev/docs/hooks#server-hooks-handle).
 	 */
@@ -492,7 +492,7 @@ export interface RequestEvent<
 	 *
 	 * You cannot add a `set-cookie` header with `setHeaders` — use the [`cookies`](https://kit.svelte.dev/docs/types#sveltejs-kit-cookies) API instead.
 	 */
-	setHeaders: (headers: Record<string, string>) => void;
+	setHeaders(headers: Record<string, string>): void;
 	/**
 	 * The URL of the current page or endpoint
 	 */
@@ -511,8 +511,8 @@ export interface RequestHandler<
 }
 
 export interface ResolveOptions {
-	transformPageChunk?: (input: { html: string; done: boolean }) => MaybePromise<string | undefined>;
-	filterSerializedResponseHeaders?: (name: string, value: string) => boolean;
+	transformPageChunk?(input: { html: string; done: boolean }): MaybePromise<string | undefined>;
+	filterSerializedResponseHeaders?(name: string, value: string): boolean;
 }
 
 export class Server {
@@ -540,7 +540,7 @@ export interface SSRManifest {
 		};
 		nodes: SSRNodeLoader[];
 		routes: SSRRoute[];
-		matchers: () => Promise<Record<string, ParamMatcher>>;
+		matchers(): Promise<Record<string, ParamMatcher>>;
 	};
 }
 
@@ -565,7 +565,7 @@ export interface ServerLoadEvent<
 	 *
 	 * Be careful not to introduce accidental waterfalls when using `await parent()`. If for example you only want to merge parent data into the returned output, call it _after_ fetching your other data.
 	 */
-	parent: () => Promise<ParentData>;
+	parent(): Promise<ParentData>;
 	/**
 	 * This function declares that the `load` function has a _dependency_ on one or more URLs or custom identifiers, which can subsequently be used with [`invalidate()`](/docs/modules#$app-navigation-invalidate) to cause `load` to rerun.
 	 *
@@ -603,7 +603,7 @@ export interface ServerLoadEvent<
 	 * <button on:click={increase}>Increase Count</button>
 	 * ```
 	 */
-	depends: (...deps: string[]) => void;
+	depends(...deps: string[]): void;
 }
 
 export interface Action<
diff --git a/packages/kit/types/internal.d.ts b/packages/kit/types/internal.d.ts
index 80f82653d..fb5090e04 100644
--- a/packages/kit/types/internal.d.ts
+++ b/packages/kit/types/internal.d.ts
@@ -83,7 +83,7 @@ export type CSRPageNodeLoader = () => Promise<CSRPageNode>;
  */
 export type CSRRoute = {
 	id: string;
-	exec: (path: string) => undefined | Record<string, string>;
+	exec(path: string): undefined | Record<string, string>;
 	errors: Array<CSRPageNodeLoader | undefined>;
 	layouts: Array<[boolean, CSRPageNodeLoader] | undefined>;
 	leaf: [boolean, CSRPageNodeLoader];
@@ -260,7 +260,7 @@ export interface SSRNode {
 	/** external CSS files */
 	stylesheets: string[];
 	/** inlined styles */
-	inline_styles?: () => MaybePromise<Record<string, string>>;
+	inline_styles?(): MaybePromise<Record<string, string>>;
 
 	shared: {
 		load?: Load;
@@ -343,7 +343,7 @@ export interface SSRRoute {
 
 export interface SSRState {
 	fallback?: string;
-	getClientAddress: () => string;
+	getClientAddress(): string;
 	initiator?: SSRRoute | SSRErrorPage;
 	platform?: any;
 	prerendering?: PrerenderOptions;
diff --git a/packages/kit/types/private.d.ts b/packages/kit/types/private.d.ts
index 36ed7cfbe..8a573a104 100644
--- a/packages/kit/types/private.d.ts
+++ b/packages/kit/types/private.d.ts
@@ -15,15 +15,15 @@ export interface AdapterEntry {
 	 * if it should be treated as a fallback for the current route. For example, `/foo/[c]`
 	 * is a fallback for `/foo/a-[b]`, and `/[...catchall]` is a fallback for all routes
 	 */
-	filter: (route: RouteDefinition) => boolean;
+	filter(route: RouteDefinition): boolean;
 
 	/**
 	 * A function that is invoked once the entry has been created. This is where you
 	 * should write the function to the filesystem and generate redirect manifests.
 	 */
-	complete: (entry: {
-		generateManifest: (opts: { relativePath: string; format?: 'esm' | 'cjs' }) => string;
-	}) => MaybePromise<void>;
+	complete(entry: {
+		generateManifest(opts: { relativePath: string; format?: 'esm' | 'cjs' }): string;
+	}): MaybePromise<void>;
 }
 
 // Based on https://github.com/josh-hemphill/csp-typed-directives/blob/latest/src/csp.types.ts
@@ -195,7 +195,7 @@ export type PrerenderOption = boolean | 'auto';
 export type PrerenderMap = Map<string, PrerenderOption>;
 
 export interface RequestOptions {
-	getClientAddress: () => string;
+	getClientAddress(): string;
 	platform?: App.Platform;
 }
 
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 89b38f560..9a5f12e42 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -266,7 +266,7 @@ importers:
   packages/kit:
     specifiers:
       '@playwright/test': ^1.25.0
-      '@sveltejs/vite-plugin-svelte': ^1.0.5
+      '@sveltejs/vite-plugin-svelte': ^1.1.0
       '@types/connect': ^3.4.35
       '@types/cookie': ^0.5.1
       '@types/marked': ^4.0.7
@@ -292,7 +292,7 @@ importers:
       uvu: ^0.5.3
       vite: ^3.1.1
     dependencies:
-      '@sveltejs/vite-plugin-svelte': 1.0.5_svelte@3.48.0+vite@3.1.1
+      '@sveltejs/vite-plugin-svelte': 1.1.0_svelte@3.48.0+vite@3.1.1
       '@types/cookie': 0.5.1
       cookie: 0.5.0
       devalue: 4.0.0
@@ -1155,8 +1155,8 @@ packages:
       golden-fleece: 1.0.9
     dev: true
 
-  /@sveltejs/vite-plugin-svelte/1.0.5_svelte@3.48.0+vite@3.1.1:
-    resolution: {integrity: sha512-CmSdSow0Dr5ua1A11BQMtreWnE0JZmkVIcRU/yG3PKbycKUpXjNdgYTWFSbStLB0vdlGnBbm2+Y4sBVj+C+TIw==}
+  /@sveltejs/vite-plugin-svelte/1.1.0_svelte@3.48.0+vite@3.1.1:
+    resolution: {integrity: sha512-cFRfEdztubtj1c/rYh7ArK7XCfFJn6wG6+J8/e9amFsKtEJILovoBrK0/mxt1AjPQg0vaX+fHPKvhx+q8mTPaQ==}
     engines: {node: ^14.18.0 || >= 16}
     peerDependencies:
       diff-match-patch: ^1.0.5
@@ -1166,13 +1166,12 @@ packages:
       diff-match-patch:
         optional: true
     dependencies:
-      '@rollup/pluginutils': 4.2.1
       debug: 4.3.4
       deepmerge: 4.2.2
       kleur: 4.1.5
-      magic-string: 0.26.3
+      magic-string: 0.26.7
       svelte: 3.48.0
-      svelte-hmr: 0.14.12_svelte@3.48.0
+      svelte-hmr: 0.15.0_svelte@3.48.0
       vite: 3.1.1
     transitivePeerDependencies:
       - supports-color
@@ -2935,6 +2934,7 @@ packages:
     engines: {node: '>=12'}
     dependencies:
       sourcemap-codec: 1.4.8
+    dev: true
 
   /magic-string/0.26.6:
     resolution: {integrity: sha512-6d+3bFybzyQFJYSoRsl9ZC0wheze8M1LrQC7tNMRqXR4izUTDOLMd9BtSuExK9iAukFh+s5K0WAhc/dlQ+HKYA==}
@@ -2942,6 +2942,13 @@ packages:
     dependencies:
       sourcemap-codec: 1.4.8
 
+  /magic-string/0.26.7:
+    resolution: {integrity: sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow==}
+    engines: {node: '>=12'}
+    dependencies:
+      sourcemap-codec: 1.4.8
+    dev: false
+
   /make-dir/3.1.0:
     resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
     engines: {node: '>=8'}
@@ -4124,8 +4131,8 @@ packages:
       - sugarss
     dev: true
 
-  /svelte-hmr/0.14.12_svelte@3.48.0:
-    resolution: {integrity: sha512-4QSW/VvXuqVcFZ+RhxiR8/newmwOCTlbYIezvkeN6302YFRE8cXy0naamHcjz8Y9Ce3ITTZtrHrIL0AGfyo61w==}
+  /svelte-hmr/0.15.0_svelte@3.48.0:
+    resolution: {integrity: sha512-Aw21SsyoohyVn4yiKXWPNCSW2DQNH/76kvUnE9kpt4h9hcg9tfyQc6xshx9hzgMfGF0kVx0EGD8oBMWSnATeOg==}
     engines: {node: ^12.20 || ^14.13.1 || >= 16}
     peerDependencies:
       svelte: '>=3.19.0'


Test patch:
diff --git a/packages/kit/test/utils.d.ts b/packages/kit/test/utils.d.ts
index 6bf48601a..a1958487e 100644
--- a/packages/kit/test/utils.d.ts
+++ b/packages/kit/test/utils.d.ts
@@ -13,19 +13,19 @@ export const test: TestType<
 	PlaywrightTestArgs &
 		PlaywrightTestOptions & {
 			app: {
-				goto: (url: string, opts?: { replaceState?: boolean }) => Promise<void>;
-				invalidate: (url: string) => Promise<void>;
-				beforeNavigate: (url: URL) => void | boolean;
-				afterNavigate: (url: URL) => void;
-				prefetch: (url: string) => Promise<void>;
-				prefetchRoutes: (urls: string[]) => Promise<void>;
+				goto(url: string, opts?: { replaceState?: boolean }): Promise<void>;
+				invalidate(url: string): Promise<void>;
+				beforeNavigate(url: URL): void | boolean;
+				afterNavigate(url: URL): void;
+				prefetch(url: string): Promise<void>;
+				prefetchRoutes(urls: string[]): Promise<void>;
 			};
-			clicknav: (selector: string, options?: { timeout?: number }) => Promise<void>;
-			in_view: (selector: string) => Promise<boolean>;
+			clicknav(selector: string, options?: { timeout?: number }): Promise<void>;
+			in_view(selector: string): Promise<boolean>;
 			/**
 			 * `handleError` defines the shape
 			 */
-			read_errors: (href: string) => Record<string, any>;
+			read_errors(href: string): Record<string, any>;
 		},
 	PlaywrightWorkerArgs & PlaywrightWorkerOptions
 >;
@@ -37,7 +37,7 @@ export const start_server: (
 	start?: number
 ) => Promise<{
 	port: number;
-	close: () => Promise<void>;
+	close(): Promise<void>;
 }>;
 
 export const plugin: () => Plugin;
diff --git a/packages/kit/test/utils.js b/packages/kit/test/utils.js
index d689b62e2..ed1c58d0b 100644
--- a/packages/kit/test/utils.js
+++ b/packages/kit/test/utils.js
@@ -56,10 +56,11 @@ export const test = base.extend({
 		 * @param {{ timeout: number }} options
 		 */
 		async function clicknav(selector, options) {
+			const element = page.locator(selector);
 			if (javaScriptEnabled) {
-				await Promise.all([page.waitForNavigation(options), page.click(selector)]);
+				await Promise.all([page.waitForNavigation(options), element.click()]);
 			} else {
-				await page.click(selector);
+				await element.click();
 			}
 		}