Back to Intro to Storybook
Chapters
  • Inizia
  • Componente semplice
  • Componente composito
  • Dati
  • Schermate
  • Deploy
  • Visual Testing
  • Addons
  • Conclusione
  • Contribuisci

Costruisci una schermata

Costruisci una schermata da componenti
Questa traduzione della comunità non è stata ancora aggiornata all'ultima versione di Storybook. Aiutaci ad aggiornarlo applicando le modifiche nella guida italiana per questa traduzione. Pull requests sono benvenute.

Ci siamo concentrati sulla costruzione di interfacce utente dal basso verso l'alto, partendo da piccole e aggiungendo complessità. Farlo ci ha permesso di sviluppare ogni componente in isolamento, capire le sue esigenze di dati e giocare con esso in Storybook. Tutto senza dover avviare un server o costruire schermate!

In questo capitolo, continuiamo ad aumentare la sofisticatezza combinando i componenti in una schermata e sviluppando quella schermata in Storybook.

Componenti del contenitore annidati

Siccome la nostra applicazione è semplice, lo schermo che costruiremo è abbastanza banale, semplicemente avvolgendo il componente TaskList (che fornisce i propri dati tramite Pinia) in qualche layout e lancia un errore di primo livello fuori dallo store (supponendo di impostare quel campo se abbiamo qualche problema di connessione al nostro server). Creiamo un PureInboxScreen.vue di presentazione nella cartella src/components/ :

Copy
src/components/PureInboxScreen.vue
<template>
  <div>
    <div v-if="error" class="page lists-show">
      <div class="wrapper-message">
        <span class="icon-face-sad" />
        <p class="title-message">Oh no!</p>
        <p class="subtitle-message">Something went wrong</p>
      </div>
    </div>
    <div v-else class="page lists-show">
      <nav>
        <h1 class="title-page">Taskbox</h1>
      </nav>
      <TaskList />
    </div>
  </div>
</template>

<script>
import TaskList from './TaskList.vue';
export default {
  name: 'PureInboxScreen',
  components: { TaskList },
  props: {
    error: { type: Boolean, default: false },
  },
};
</script>

Poi, possiamo creare un contenitore, che di nuovo prende i dati per la PureInboxScreen in src/components/InboxScreen.vue:

Copy
src/components/InboxScreen.vue
<template>
  <PureInboxScreen :error="isError" />
</template>

<script>
import PureInboxScreen from './PureInboxScreen.vue';

import { computed } from 'vue';

import { useTaskStore } from '../store';

export default {
  name: 'InboxScreen',
  components: { PureInboxScreen },
  setup() {
    //👇 Creates a store instance
    const store = useTaskStore();

    //👇 Retrieves the error from the store's state
    const isError = computed(() => store.status==='error');
    return {
      isError,
    };
  },
};
</script>

Successivamente, dovremo aggiornare il punto di ingresso della nostra app (src/main.js) in modo da poter collegare lo store nella nostra gerarchia di componenti velocemente:

Copy
src/main.js
import { createApp } from 'vue';
+ import { createPinia } from 'pinia';

import App from './App.vue';

- createApp(App).mount('#app')
+ createApp(App).use(createPinia()).mount('#app');

Dobbiamo anche cambiare il componente App per rendere la InboxScreen (alla fine, useremmo un router per scegliere la schermata corretta, ma non preoccupiamoci di questo ora):

Copy
src/App.vue
<script setup>
import InboxScreen from './components/InboxScreen.vue';
</script>

<template>
  <div id="app">
    <InboxScreen />
  </div>
</template>

<style>
@import './index.css';
</style>

Tuttavia, le cose diventano interessanti quando si tratta di renderizzare la storia in Storybook.

Come abbiamo visto in precedenza, il componente TaskList è un container* che renderizza il componente di presentazione PureTaskList. Per definizione, i componenti del container non possono essere semplicemente renderrizzati in modo isolato; si aspettano di essere passati a qualche contesto o connessi a un servizio. Ciò significa che per renderizzare un contenitore in Storybook, dobbiamo simulare (cioè fornire una versione finta) il contesto o il servizio che richiede.

Posizionando la TaskList in Storybook, siamo stati in grado di evitare questo problema semplicemente renderizzando la PureTaskList ed evitando il contenitore. Faremo qualcosa di simile e renderizzeremo anche il PureInboxScreen in Storybook.

Mettendo la TaskList in Storybook, siamo stati in grado di schivare questo problema semplicemente renderizzando la PureTaskList ed evitando il contenitore. Faremo qualcosa di simile e rendere il PureInboxScreen in Storybook anche.

Tuttavia, abbiamo un problema con la PureInboxScreen perché anche se la PureInboxScreen stessa è presentazionale, il figlio, TaskList, non lo è. In un certo senso, il PureInboxScreen è stato inquinato dal fatto di non avere un contenitore. Così quando abbiamo impostato le nostre storie in src/components/PureInboxScreen.stories.js:

Copy
src/components/PureInboxScreen.stories.js
import PureInboxScreen from './PureInboxScreen.vue';

export default {
  component: PureInboxScreen,
  title: 'PureInboxScreen',
  tags: ['autodocs'],
};

export const Default = {};

export const Error = {
  args: { error: true },
};

Vediamo che anche se la storia d'errore funziona bene, abbiamo un problema nella storia default perché la TaskList non ha lo store di Pinia per connettersi.

Inbox rotto

Un modo per eludere questo problema è quello di non renderizzare mai i componenti del contenitore in qualsiasi punto della vostra applicazione, tranne al più alto livello e invece passare tutti i dati necessari lungo la gerarchia dei componenti.

Tuttavia, gli sviluppatori dovranno inevitabilmente renderizzare i contenitori più in basso nella gerarchia dei componenti. Se vogliamo renderizzare la maggior parte dell'app o tutta in Storybook (lo vogliamo!), abbiamo bisogno di una soluzione a questo problema.

💡 Come suggerimento aggiuntivo, un altro approccio valido sarebbe quello di passare i dati lungo la gerarchia, specialmente quando si utilizza GraphQL. È così che abbiamo costruito Chromatic insieme a più di 800 storie.

Fornire contesto alle storie

La buona notizia è che è facile collegare Storybook ad uno store Pinia e riutilizzarlo tra storie! Possiamo aggiornare il nostro file di configurazione .storybook/preview.js e fare affidamento sulla funzione setup di Storybook per registrare il nostro negozio Pinia:

Copy
.storybook/preview.js
+ import { setup } from '@storybook/vue3';

+ import { createPinia } from 'pinia';

import '../src/index.css';

//👇 Registers a global Pinia instance inside Storybook to be consumed by existing stories
+ setup((app) => {
+   app.use(createPinia());
+ });

/** @type { import('@storybook/vue3').Preview } */
const preview = {
  parameters: {
    actions: { argTypesRegex: '^on[A-Z].*' },
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/,
      },
    },
  },
};

export default preview;

Approcci simili esistono per fornire un contesto finto per altre librerie di dati, come Apollo, Relay e altre.

Scorrere attraverso gli stati di Storybook rende facile testare, abbiamo fatto questo correttamente:

Test sulle interazioni

Finora, siamo stati in grado di costruire un'applicazione completamente funzionale partendo da zero, iniziando da un semplice componente fino ad arrivare a una schermata, testando continuamente ogni modifica con le nostre storie. Ma ogni nuova storia richiede anche un controllo manuale su tutte le altre storie per assicurarsi che l'interfaccia utente non si rompa. È un sacco di lavoro extra.

Non possiamo automatizzare questo flusso di lavoro e testare automaticamente le interazioni dei nostri componenti?

Scrivi un test di interazione usando la funzione play

Gli strumenti di Storybook play e @storybook/addon-interactions ci aiutano in questo. Una funzione play include piccoli frammenti di codice che vengono eseguiti dopo il rendering della storia.

La funzione play ci aiuta a verificare cosa succede all'UI quando i task vengono aggiornati. Utilizza API DOM indipendenti dal framework, il che significa che possiamo scrivere storie con la funzione play per interagire con l'UI e simulare il comportamento umano indipendentemente dal framework frontend utilizzato.

L'@storybook/addon-interactions ci aiuta a visualizzare i nostri test in Storybook, fornendo un flusso passo-passo. Offre anche un pratico set di controlli dell'interfaccia utente per mettere in pausa, riprendere, riavvolgere e passare attraverso ogni interazione.

Vediamolo in azione! Aggiorna la tua storia PureInboxScreen appena creata e configura le interazioni del componente aggiungendo quanto segue:

Copy
src/components/PureInboxScreen.stories.js
import PureInboxScreen from './PureInboxScreen.vue';

+ import { fireEvent, within } from '@storybook/test';

export default {
  component: PureInboxScreen,
  title: 'PureInboxScreen',
  tags: ['autodocs'],
};

export const Default = {};

export const Error = {
  args: { error: true },
};

+ export const WithInteractions = {
+  play: async ({ canvasElement }) => {
+    const canvas = within(canvasElement);
+    // Simulates pinning the first task
+    await fireEvent.click(canvas.getByLabelText('pinTask-1'));
+    // Simulates pinning the third task
+    await fireEvent.click(canvas.getByLabelText('pinTask-3'));
+  },
+ };

💡 Il pacchetto @storybook/test sostituisce i pacchetti di test @storybook/jest e @storybook/testing-library offrendo una dimensione bundle più piccola e un'API più semplice basata sul pacchetto Vitest.

Controlla la storia Default. Clicca sul pannello Interactions per vedere l'elenco delle interazioni all'interno della funzione play della storia.

Automatizzare i test con il test runner

Con la funzione play di Storybook, siamo riusciti a evitare il nostro problema, permettendoci di interagire con la nostra UI e di controllare rapidamente come reagisce se aggiorniamo i nostri task—mantenendo l'UI coerente senza sforzo manuale aggiuntivo.

Tuttavia, se osserviamo più da vicino il nostro Storybook, possiamo vedere che esegue i test di interazione solo quando visualizziamo la storia. Quindi, dovremmo comunque passare attraverso ogni storia per eseguire tutti i controlli se apportiamo una modifica. Non potremmo automatizzarlo?

La buona notizia è che possiamo! Il test runner di Storybook ci permette di fare proprio questo. È uno strumento autonomo—alimentato da Playwright—che esegue tutti i nostri test di interazione e individua le storie rotte.

Vediamo come funziona! Esegui il seguente comando per installarlo:

Copy
yarn add --dev @storybook/test-runner

Successivamente, aggiorna la sezione scripts del tuo package.json e aggiungi un nuovo task di test:

{
  "scripts": {
    "test-storybook": "test-storybook"
  }
}

Infine, con il tuo Storybook in esecuzione, apri una nuova finestra del terminale ed esegui il seguente comando:

Copy
yarn test-storybook --watch
💡 Il testing delle interazioni con la funzione play è un modo fantastico per testare i tuoi componenti UI. Può fare molto di più di quanto abbiamo visto qui; ti consigliamo di leggere la documentazione ufficiale per saperne di più.
Per un'analisi ancora più approfondita sui test, dai un'occhiata al Manuale dei Test. Copre le strategie di test utilizzate dai team di frontend scalabili per potenziare il tuo flusso di lavoro di sviluppo.

Il test runner di Storybook esegue con successo tutti i test

Successo! Ora abbiamo uno strumento che ci aiuta a verificare se tutte le nostre storie vengono renderizzate senza errori e tutte le asserzioni passano automaticamente. Inoltre, se un test fallisce, fornirà un link che apre la storia fallita nel browser.

Sviluppo guidato dai componenti

Abbiamo iniziato dal basso con Task, poi siamo passati a TaskList, e ora siamo qui con un'intera interfaccia utente della schermata. Il nostro InboxScreen ospita componenti connessi e include storie di accompagnamento.

Sviluppo guidato dai componenti ti permette di espandere gradualmente la complessità mentre sali nella gerarchia dei componenti. Tra i vantaggi ci sono un processo di sviluppo più focalizzato e una copertura maggiore di tutte le possibili permutazioni dell'UI. In breve, il CDD ti aiuta a costruire interfacce utente di qualità superiore e più complesse.

Non abbiamo ancora finito - il lavoro non termina quando l'UI è costruita. Dobbiamo anche assicurarci che rimanga solida nel tempo.

💡 Non dimenticare di committare le tue modifiche con git!
Keep your code in sync with this chapter. View af51337 on GitHub.
Is this free guide helping you? Tweet to give kudos and help other devs find it.
Next Chapter
Deploy
Impara come effettuare il deploy di Storybook online
✍️ Edit on GitHub – PRs welcome!
Join the community
6,623 developers and counting
WhyWhy StorybookComponent-driven UI
Open source software
Storybook

Maintained by
Chromatic
Special thanks to Netlify and CircleCI