Skip to content

Commit

Permalink
e2e testing of nested lists
Browse files Browse the repository at this point in the history
Route for testing nested lists has been added to e2e/sveltekit,

Modles have been added to the e2e/_api GQL schema, and a simple
"database" with sample data has been added to the resolvers.

Signed-off-by: Jonas Jacobsen <[email protected]>
  • Loading branch information
Joklost committed Nov 5, 2022
1 parent 38ecbe7 commit 57b3777
Show file tree
Hide file tree
Showing 11 changed files with 292 additions and 1 deletion.
107 changes: 106 additions & 1 deletion e2e/_api/graphql.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,41 @@ export const typeDefs = sourceFiles.map((filepath) =>
fs.readFileSync(path.resolve(filepath), 'utf-8')
)

// Example Cities/Libraries/Books data
// Assume a traditional relational database for storage - each table with unique ID.
let cityId = 1;
let libraryId = 1;
let bookId = 1;

// Allow the "database" to be persistent and mutable
let cities = [
{
id: cityId++, name: 'Alexandria', libraries: [
{
id: libraryId++, name: 'The Library of Alexandria', books: [
{ id: bookId++, title: 'Callimachus Pinakes' },
{ id: bookId++, title: 'Kutubkhana-i-lskandriyya' },
]
},
{
id: libraryId++, name: 'Bibliotheca Alexandrina', books: [
{ id: bookId++, title: 'Analyze your own personality' },
]
},
]
},
{
id: cityId++, name: 'Istanbul', libraries: [
{
id: libraryId++, name: 'The Imperial Library of Constantinople', books: [
{ id: bookId++, title: 'Homer' },
{ id: bookId++, title: 'The Hellenistic History' },
]
},
]
},
];

// example data
const data = [
{ id: '1', name: 'Bruce Willis', birthDate: new Date(1955, 2, 19) },
Expand Down Expand Up @@ -100,6 +135,9 @@ export const resolvers = {
__typename: 'User',
}
},
cities: () => {
return cities;
},
},

User: {
Expand Down Expand Up @@ -149,7 +187,7 @@ export const resolvers = {
try {
let data = await processFile(file)
return data
} catch (e) {}
} catch (e) { }
throw new GraphQLYogaError('ERROR', { code: 500 })
},
multipleUpload: async (_, { files }) => {
Expand All @@ -164,6 +202,73 @@ export const resolvers = {
}
return res
},
addCity: (_, args) => {
const city = {
id: cityId++,
name: args.name,
libraries: [],
}

cities.push(city);
return city;
},
addLibrary: (_, args) => {
const cityId = Number.parseInt(args.city);
const city = cities.find((city) => city.id === cityId);
if (!city) {
throw new GraphQLYogaError('City not found', { code: 404 })
}

const library = {
id: libraryId++,
name: args.name,
books: [],
}
city.libraries.push(library);
return library;
},
addBook: (_, args) => {
const libraryId = Number.parseInt(args.library);
const city = cities.find((city) => city.libraries.find((library) => library.id === libraryId));
if (!city) {
throw new GraphQLYogaError('City/Library not found', { code: 404 })
}
const library = city.libraries.find((library) => library.id === libraryId);

const book = {
id: bookId++,
title: args.title,
}
library.books.push(book);
return book;
},
deleteCity: (_, args) => {
const cityId = Number.parseInt(args.city);
const city = cities.find((city) => city.id === cityId);
cities = cities.filter((city) => city.id !== cityId);
return city;
},
deleteLibrary: (_, args) => {
const libraryId = Number.parseInt(args.library);
const city = cities.find((city) => city.libraries.find((library) => library.id === libraryId));
if (!city) {
throw new GraphQLYogaError('City/Library not found', { code: 404 })
}
const library = city.libraries.find((library) => library.id === libraryId);
city.libraries = city.libraries.filter((library) => library.id !== libraryId);
return library;
},
deleteBook: (_, args) => {
const bookId = Number.parseInt(args.book);
const city = cities.find((city) => city.libraries.find((library) => library.books.find((book) => book.id === bookId)));
if (!city) {
throw new GraphQLYogaError('City/Library/Book not found', { code: 404 })
}
const library = city.libraries.find((library) => library.books.find((book) => book.id === bookId));
const book = library.books.find((book) => book.id === bookId);
library.books = library.books.filter((book) => book.id !== bookId);
return book;
},
},

DateTime: new GraphQLScalarType({
Expand Down
39 changes: 39 additions & 0 deletions e2e/_api/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,26 @@ type Mutation {
updateUser(id: ID!, name: String, snapshot: String!, birthDate: DateTime, delay: Int): User!
singleUpload(file: File!): String!
multipleUpload(files: [File!]!): [String!]!
addCity(
name: String!
): City!
addLibrary(
city: ID!
name: String!
): Library!
addBook(
library: ID!
title: String!
): Book!
deleteCity(
city: ID!
): City!
deleteLibrary(
library: ID!
): Library!
deleteBook(
book: ID!
): Book!
}

interface Node {
Expand All @@ -52,6 +72,7 @@ type Query {
): UserConnection!
usersList(limit: Int = 4, offset: Int, snapshot: String!): [User!]!
session: String
cities: [City]!
}

type User implements Node {
Expand All @@ -73,3 +94,21 @@ type UserEdge {
cursor: String
node: User
}


type Book {
id: ID!
title: String!
}

type Library {
id: ID!
name: String!
books: [Book]!
}

type City {
id: ID!
name: String!
libraries: [Library]!
}
6 changes: 6 additions & 0 deletions e2e/sveltekit/src/lib/graphql/operations/MUTATION.AddBook.gql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
mutation AddBook($library: ID!, $title: String!) {
addBook(library: $library, title: $title) {
id
...Book_List_insert @append(parentID: $library)
}
}
6 changes: 6 additions & 0 deletions e2e/sveltekit/src/lib/graphql/operations/MUTATION.AddCity.gql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
mutation AddCity($name: String!) {
addCity(name: $name) {
id
...City_List_insert
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
mutation AddLibrary($city: ID!, $name: String!) {
addLibrary(city: $city, name: $name) {
id
...Library_List_insert @append(parentID: $city)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mutation DeleteBook($book: ID!) {
deleteBook(book: $book) {
id @Book_delete
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mutation DeleteCity($city: ID!) {
deleteCity(city: $city) {
id @City_delete
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mutation DeleteLibrary($library: ID!) {
deleteLibrary(library: $library) {
id @Library_delete
}
}
14 changes: 14 additions & 0 deletions e2e/sveltekit/src/lib/graphql/operations/QUERY.Cities.gql
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
query Cities {
cities @list(name: "City_List") {
id
name
libraries @list(name: "Library_List") {
id
name
books @list(name: "Book_List") {
id
title
}
}
}
}
2 changes: 2 additions & 0 deletions e2e/sveltekit/src/lib/utils/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ export const routes = {
Pagination_fragment_backwards_cursor: '/pagination/fragment/backwards-cursor',
Pagination_fragment_offset: '/pagination/fragment/offset',

Stores_Nested_List: '/stores/nested-list',

Stores_subunsub_list: '/stores/subunsub-list',
Stores_subunsub_mutation: '/stores/subunsub-mutation',

Expand Down
98 changes: 98 additions & 0 deletions e2e/sveltekit/src/routes/stores/nested-list/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<script lang="ts">
import { browser } from '$app/environment';
import {
GQL_Cities,
GQL_AddCity,
GQL_AddLibrary,
GQL_AddBook,
GQL_DeleteCity,
GQL_DeleteLibrary,
GQL_DeleteBook
} from '$houdini';
$: browser && GQL_Cities.fetch();
const addCity = (event: Event) => {
const target = event?.target as HTMLInputElement;
GQL_AddCity.mutate({ name: target.value });
target.value = '';
};
const deleteCity = (event: Event) => {
const target = event?.target as HTMLButtonElement;
if (!target.dataset.id) {
return;
}
GQL_DeleteCity.mutate({ city: target.dataset.id });
};
const addLibrary = (event: Event) => {
const target = event?.target as HTMLInputElement;
if (!target.dataset.id) {
return;
}
GQL_AddLibrary.mutate({ city: target.dataset.id, name: target.value });
target.value = '';
};
const deleteLibrary = (event: Event) => {
const target = event?.target as HTMLButtonElement;
if (!target.dataset.id) {
return;
}
GQL_DeleteLibrary.mutate({ library: target.dataset.id });
};
const addBook = (event: Event) => {
const target = event?.target as HTMLInputElement;
if (!target.dataset.id) {
return;
}
GQL_AddBook.mutate({ library: target.dataset.id, title: target.value });
target.value = '';
};
const deleteBook = (event: Event) => {
const target = event?.target as HTMLButtonElement;
if (!target.dataset.id) {
return;
}
GQL_DeleteBook.mutate({ book: target.dataset.id });
};
</script>

<h1>Nested - List</h1>

<ul>
{#each $GQL_Cities.data?.cities ?? [] as city}
<li>
{city?.id}: {city?.name}
<button data-id={city?.id} on:click={deleteCity}>Delete</button>
<ul>
{#each city?.libraries ?? [] as library}
<li>
{library?.id}: {library?.name}
<button data-id={library?.id} on:click={deleteLibrary}>Delete</button>
<ul>
{#each library?.books ?? [] as book}
<li>
{book?.id}: {book?.title}
<button data-id={book?.id} on:click={deleteBook}>Delete</button>
</li>
{/each}
<li><input data-id={library?.id} on:change={addBook} /></li>
</ul>
</li>
{/each}
<li><input data-id={city?.id} on:change={addLibrary} /></li>
</ul>
</li>
{/each}
<li>
<input on:change={addCity} />
</li>
</ul>

<pre>{JSON.stringify($GQL_Cities?.data, null, 4)}</pre>

0 comments on commit 57b3777

Please sign in to comment.