Quantcast
Channel: Active questions tagged svelte - Stack Overflow
Viewing all articles
Browse latest Browse all 1882

$effect “forgets” state change, test crashes with “Cannot read properties of undefined”

$
0
0

I’m trying to write a Vitest unit test for an auto-save feature in a Svelte 5 project.The test sets meta.settings.autoSaveIntervalMs = 50 so the save cycle finishes quickly, but the $effect still uses the old value 5000, nothing seems to be written to IndexedDB, and load() returns undefined, crashing the assertion.Below are the relevant file code.

  1. model.ts
export interface ProjectMeta {  title: string;  settings: { autoSaveIntervalMs: number };}
  1. state.svelte.ts (reactive central state manager)
import { type ProjectMeta } from './model';import { persist, load } from './persistence';export const createProjectMeta = (title = 'Untitled'): ProjectMeta => ({  title,  settings: { autoSaveIntervalMs: 5_000 },});export const meta = $state<ProjectMeta>(createProjectMeta());export function startAutoSave() {  $effect(() => {    // shallow copy captured once    const dirty = { meta: { ...meta } };    const handle = setInterval(() => {      persist(dirty);      console.log('Autosaving', dirty);    }, meta.settings.autoSaveIntervalMs);    return () => clearInterval(handle);  });  $inspect(meta);}
  1. persistence.ts (Dexie)
import Dexie from 'dexie';import type { ProjectMeta } from './model';interface Persisted { meta: ProjectMeta; }type PersistedSerialized = Persisted;const db = new (class extends Dexie {  project!: Dexie.Table<PersistedSerialized, string>;  constructor() {    super('persist-on-interval');    this.version(1).stores({ project: '' });  }})();export const persist = (data: { meta: ProjectMeta }) => {  console.log('About to store:', data);  return db.project.put(data, 'main');};export const load = async () => {  const raw = await db.project.get('main');  console.log('Raw from DB;', raw);  return raw ?? null;};
  1. TestShell.svelte
<script>  import { startAutoSave } from './state.svelte';  startAutoSave();</script>
  1. state.svelte.test.ts (the failing test)
import { describe, it, expect, beforeEach } from 'vitest';import { render, waitFor } from '@testing-library/svelte';import TestShell from './TestShell.svelte';import { meta } from './state.svelte';import { load } from './persistence';describe('State manager', () => {  beforeEach(() => {    Object.assign(meta, createProjectMeta());  });  it('persists on interval', async () => {    // speed up the interval    meta.settings.autoSaveIntervalMs = 50;    render(TestShell);                // starts the $effect    await waitFor(() => document.body);    meta.title = 'Renamed title for auto-save';    // wait at least one cycle    await new Promise(r => setTimeout(r, 100));    const restored = await load();    expect(restored!.meta.title).toBe('Renamed title for auto-save');  });});

Here's what observed in the console:

init { title: 'Untitled', settings: { autoSaveIntervalMs: 50 } }update { title: 'Renamed title for auto-save', settings: { autoSaveIntervalMs: 50 } }Autosaving { meta: { title: 'Renamed title for auto-save', settings: { autoSaveIntervalMs: 5000 } } }About to store: { meta: { title: 'Renamed title for auto-save', settings: { autoSaveIntervalMs: 5000 } } }Raw from DB: undefined

Problem summary

  • In the test I set meta.settings.autoSaveIntervalMs = 50.
  • The $effect runs once, captures a shallow copy of meta, then schedules setInterval(..., meta.settings.autoSaveIntervalMs /* 50 */).
  • Yet the very first autosave log shows autoSaveIntervalMs: 5000 again, proving the copy is stale.
  • After 100 ms, load() returns undefined, so the test explodes with TypeError: Cannot read properties of undefined (reading 'meta').

I have tried changing the timeout period in the test, waiting for TestShell to successfully mount (as seen in the test), etc. but still got back raw (in load()) as undefined.

My questions:

  1. Why doesn’t the $effect re-run (and grab a fresh copy) when meta.settings.autoSaveIntervalMs changes?
  2. Am I missing some Dexie/Vitest quirk that causes the store to come back undefined even when data should have been written?

Any pointers would be greatly appreciated!


Viewing all articles
Browse latest Browse all 1882

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>