Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Specs For Searches #3199

Closed
wants to merge 18 commits into from
Closed

feat: Specs For Searches #3199

wants to merge 18 commits into from

Conversation

Tirokk
Copy link
Member

@Tirokk Tirokk commented Oct 5, 2020

Mogge Authored by Mogge
Mar 3, 2020
Merged Mar 18, 2020


🍰 Pullrequest

This. Adding specs for searches in Backand and improve the search queries

@Tirokk
Copy link
Member Author

Tirokk commented Oct 7, 2020

cypress[bot] Authored by cypress[bot]
Mar 3, 2020




Test summary

66 0 0 0


Run details

Project Human-Connection
Status Passed
Commit 800e33e
Started Mar 18, 2020 7:57 PM
Ended Mar 18, 2020 8:19 PM
Duration 22:19 💡
OS Linux Ubuntu Linux - 16.04
Browser Firefox 68

View run in Cypress Dashboard ➡️


This comment has been generated by cypress-bot as a result of this project's GitHub integration settings. You can manage this integration in this project's settings in the Cypress Dashboard

@Tirokk
Copy link
Member Author

Tirokk commented Oct 7, 2020

cypress[bot] Authored by cypress[bot]
Mar 3, 2020




Test summary

66 0 0 0


Run details

Project Human-Connection
Status Passed
Commit 208929dcea ℹ️
Started Mar 18, 2020 7:56 PM
Ended Mar 18, 2020 8:18 PM
Duration 21:39 💡
OS Linux Ubuntu Linux - 16.04
Browser Firefox 68

View run in Cypress Dashboard ➡️


This comment has been generated by cypress-bot as a result of this project's GitHub integration settings. You can manage this integration in this project's settings in the Cypress Dashboard

@Tirokk
Copy link
Member Author

Tirokk commented Oct 7, 2020

mattwr18 Authored by mattwr18
Mar 13, 2020


this was in the list of PRs ready for review, but then there is a WIP and a comment that the tests should be continued to be refactored, so should we give a WIP PR review, or hold off?

return `(${tmp})^${boost}`
}

const matchSomeWordsExactly = (str, boost = 2) => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mattwr18 Authored by mattwr18
Mar 16, 2020


Outdated (history rewrite) - original diff


@@ -0,0 +1,61 @@
+export function queryString(str) {
+  const normalizedString = normalizeWhitespace(str)
+  const escapedString = escapeSpecialCharacters(normalizedString)
+  return `
+${matchWholeText(escapedString)}
+${matchEachWordExactly(escapedString)}
+${matchSomeWordsExactly(escapedString)}
+${matchBeginningOfWords(escapedString)}
+`
+}
+
+const matchWholeText = (str, boost = 8) => {
+  return `"${str}"^${boost}`
+}
+
+const matchEachWordExactly = (str, boost = 4) => {
+  if (str.includes(' ')) {
+    const tmp = str
+      .split(' ')
+      .map((s, i) => (i === 0 ? `"${s}"` : `AND "${s}"`))
+      .join(' ')
+    return `(${tmp})^${boost}`
+  } else {
+    return ''
+  }
if (!str.includes(' ')) return ''
const tmp = str
  .split(' ')
  .map((s, i) => (i === 0 ? `"${s}"` : `AND "${s}"`))
  .join(' ')
return `(${tmp})^${boost}`

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mogge Authored by Mogge
Mar 17, 2020


Thanks. This is much better

.split(' ')
.map(s => `"${s}"^${boost}`)
.join(' ')
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mattwr18 Authored by mattwr18
Mar 16, 2020


Outdated (history rewrite) - original diff


@@ -0,0 +1,61 @@
+export function queryString(str) {
+  const normalizedString = normalizeWhitespace(str)
+  const escapedString = escapeSpecialCharacters(normalizedString)
+  return `
+${matchWholeText(escapedString)}
+${matchEachWordExactly(escapedString)}
+${matchSomeWordsExactly(escapedString)}
+${matchBeginningOfWords(escapedString)}
+`
+}
+
+const matchWholeText = (str, boost = 8) => {
+  return `"${str}"^${boost}`
+}
+
+const matchEachWordExactly = (str, boost = 4) => {
+  if (str.includes(' ')) {
+    const tmp = str
+      .split(' ')
+      .map((s, i) => (i === 0 ? `"${s}"` : `AND "${s}"`))
+      .join(' ')
+    return `(${tmp})^${boost}`
+  } else {
+    return ''
+  }
+}
+
+const matchSomeWordsExactly = (str, boost = 2) => {
+  if (str.includes(' ')) {
+    return str
+      .split(' ')
+      .map(s => `"${s}"^${boost}`)
+      .join(' ')
+  } else {
+    return ''
+  }
+}

favor guard clauses... see 👆

.filter(s => s.length > 3)
.map(s => s + '*')
.join(' ')
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mattwr18 Authored by mattwr18
Mar 16, 2020


Outdated (history rewrite) - original diff


@@ -0,0 +1,61 @@
+export function queryString(str) {
+  const normalizedString = normalizeWhitespace(str)
+  const escapedString = escapeSpecialCharacters(normalizedString)
+  return `
+${matchWholeText(escapedString)}
+${matchEachWordExactly(escapedString)}
+${matchSomeWordsExactly(escapedString)}
+${matchBeginningOfWords(escapedString)}
+`
+}
+
+const matchWholeText = (str, boost = 8) => {
+  return `"${str}"^${boost}`
+}
+
+const matchEachWordExactly = (str, boost = 4) => {
+  if (str.includes(' ')) {
+    const tmp = str
+      .split(' ')
+      .map((s, i) => (i === 0 ? `"${s}"` : `AND "${s}"`))
+      .join(' ')
+    return `(${tmp})^${boost}`
+  } else {
+    return ''
+  }
+}
+
+const matchSomeWordsExactly = (str, boost = 2) => {
+  if (str.includes(' ')) {
+    return str
+      .split(' ')
+      .map(s => `"${s}"^${boost}`)
+      .join(' ')
+  } else {
+    return ''
+  }
+}
+
+const matchBeginningOfWords = str => {
+  return normalizeWhitespace(
+    str
+      .split(' ')
+      .map(s => {
+        if (s.length > 3) {
+          // at least 4 letters. So AND, OR and NOT are never used unquoted
+          return s + '*'
+        } else {
+          return ''
+        }
+      })
+      .join(' '),
+  )
+}

favor guard clauses... see 👆

describe('query contains title of post', () => {
it('finds the post', async () => {
variables = { query: 'beitrag' }
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mattwr18 Authored by mattwr18
Mar 16, 2020


Outdated (history rewrite) - original diff


@@ -0,0 +1,452 @@
+import Factory, { cleanDatabase } from '../../db/factories'
+import { gql } from '../../helpers/jest'
+import { getNeode, getDriver } from '../../db/neo4j'
+import createServer from '../../server'
+import { createTestClient } from 'apollo-server-testing'
+
+let query, authenticatedUser
+
+const driver = getDriver()
+const neode = getNeode()
+
+beforeAll(async () => {
+  await cleanDatabase()
+  const { server } = createServer({
+    context: () => {
+      return {
+        driver,
+        neode,
+        user: authenticatedUser,
+      }
+    },
+  })
+  query = createTestClient(server).query
+})
+
+afterAll(async () => {
+  await cleanDatabase()
+})
+
+const searchQuery = gql`
+  query($query: String!) {
+    findResources(query: $query, limit: 5) {
+      __typename
+      ... on Post {
+        id
+        title
+        content
+      }
+      ... on User {
+        id
+        slug
+        name
+      }
+    }
+  }
+`
+let user
+
+describe('resolvers', () => {
+  describe('searches', () => {
+    let variables
+
+    describe('given one user', () => {
+      beforeAll(async () => {
+        user = await Factory.build('user', {
+          id: 'a-user',
+          name: 'John Doe',
+          slug: 'john-doe',
+        })
+        authenticatedUser = await user.toJson()
+      })
+
+      const factoryOptions = {
+        authorId: 'a-user',
+      }
+
+      describe('query contains first name of user', () => {
+        it('finds the user', async () => {
+          variables = { query: 'John' }
+          await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+            data: {
+              findResources: [
+                {
+                  id: 'a-user',
+                  name: 'John Doe',
+                  slug: 'john-doe',
+                },
+              ],
+            },
+          })
+        })
+      })
+
+      describe('adding one post', () => {
+        beforeAll(async () => {
+          await Factory.build(
+            'post',
+            {
+              id: 'a-post',
+              title: 'Beitrag',
+              content: 'Ein erster Beitrag',
+            },
+            factoryOptions,
Suggested change
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
{ author: user },

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mogge Authored by Mogge
Mar 17, 2020


I tried this first, and it did not work.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mogge Authored by Mogge
Mar 17, 2020


{ authorId: 'a-user', },

{
id: 'g-post',
title: 'Zusammengesetzte Wörter',
content: `Ein Bindestrich kann zwischen zwei Substantiven auch dann gesetzt werden, wenn drei gleichlautende Buchstaben aufeinandertreffen. Das ist etwa bei einem „Teeei“ der Fall, das so korrekt geschrieben ist. Möglich ist hier auch die Schreibweise mit Bindestrich: Tee-Ei.`,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mattwr18 Authored by mattwr18
Mar 16, 2020


Outdated (history rewrite) - original diff


@@ -0,0 +1,452 @@
+import Factory, { cleanDatabase } from '../../db/factories'
+import { gql } from '../../helpers/jest'
+import { getNeode, getDriver } from '../../db/neo4j'
+import createServer from '../../server'
+import { createTestClient } from 'apollo-server-testing'
+
+let query, authenticatedUser
+
+const driver = getDriver()
+const neode = getNeode()
+
+beforeAll(async () => {
+  await cleanDatabase()
+  const { server } = createServer({
+    context: () => {
+      return {
+        driver,
+        neode,
+        user: authenticatedUser,
+      }
+    },
+  })
+  query = createTestClient(server).query
+})
+
+afterAll(async () => {
+  await cleanDatabase()
+})
+
+const searchQuery = gql`
+  query($query: String!) {
+    findResources(query: $query, limit: 5) {
+      __typename
+      ... on Post {
+        id
+        title
+        content
+      }
+      ... on User {
+        id
+        slug
+        name
+      }
+    }
+  }
+`
+let user
+
+describe('resolvers', () => {
+  describe('searches', () => {
+    let variables
+
+    describe('given one user', () => {
+      beforeAll(async () => {
+        user = await Factory.build('user', {
+          id: 'a-user',
+          name: 'John Doe',
+          slug: 'john-doe',
+        })
+        authenticatedUser = await user.toJson()
+      })
+
+      const factoryOptions = {
+        authorId: 'a-user',
+      }
+
+      describe('query contains first name of user', () => {
+        it('finds the user', async () => {
+          variables = { query: 'John' }
+          await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+            data: {
+              findResources: [
+                {
+                  id: 'a-user',
+                  name: 'John Doe',
+                  slug: 'john-doe',
+                },
+              ],
+            },
+          })
+        })
+      })
+
+      describe('adding one post', () => {
+        beforeAll(async () => {
+          await Factory.build(
+            'post',
+            {
+              id: 'a-post',
+              title: 'Beitrag',
+              content: 'Ein erster Beitrag',
+            },
+            factoryOptions,
+          )
+        })
+
+        describe('query contains title of post', () => {
+          it('finds the post', async () => {
+            variables = { query: 'beitrag' }
+            await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+              data: {
+                findResources: [
+                  {
+                    __typename: 'Post',
+                    id: 'a-post',
+                    title: 'Beitrag',
+                    content: 'Ein erster Beitrag',
+                  },
+                ],
+              },
+            })
+          })
+        })
+
+        describe('casing', () => {
+          it('does not matter', async () => {
+            variables = { query: 'BEITRAG' }
+            await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+              data: {
+                findResources: [
+                  {
+                    __typename: 'Post',
+                    id: 'a-post',
+                    title: 'Beitrag',
+                    content: 'Ein erster Beitrag',
+                  },
+                ],
+              },
+            })
+          })
+        })
+
+        describe('query consists of words not present in the corpus', () => {
+          it('returns empty search results', async () => {
+            await expect(
+              query({ query: searchQuery, variables: { query: 'Unfug' } }),
+            ).resolves.toMatchObject({ data: { findResources: [] } })
+          })
+        })
+
+        describe('testing different post content', () => {
+          beforeAll(async () => {
+            return Promise.all([
+              Factory.build(
+                'post',
+                {
+                  id: 'b-post',
+                  title: 'Aufruf',
+                  content: 'Jeder sollte seinen Beitrag leisten.',
+                },
+                factoryOptions,
Suggested change
content: `Ein Bindestrich kann zwischen zwei Substantiven auch dann gesetzt werden, wenn drei gleichlautende Buchstaben aufeinandertreffen. Das ist etwa bei einem „Teeei“ der Fall, das so korrekt geschrieben ist. Möglich ist hier auch die Schreibweise mit Bindestrich: Tee-Ei.`,
{ author: user },

{
id: 'c-post',
title: 'Die binomischen Formeln',
content: `1. binomische Formel: (a + b)² = a² + 2ab + b²
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mattwr18 Authored by mattwr18
Mar 16, 2020


Outdated (history rewrite) - original diff


@@ -0,0 +1,452 @@
+import Factory, { cleanDatabase } from '../../db/factories'
+import { gql } from '../../helpers/jest'
+import { getNeode, getDriver } from '../../db/neo4j'
+import createServer from '../../server'
+import { createTestClient } from 'apollo-server-testing'
+
+let query, authenticatedUser
+
+const driver = getDriver()
+const neode = getNeode()
+
+beforeAll(async () => {
+  await cleanDatabase()
+  const { server } = createServer({
+    context: () => {
+      return {
+        driver,
+        neode,
+        user: authenticatedUser,
+      }
+    },
+  })
+  query = createTestClient(server).query
+})
+
+afterAll(async () => {
+  await cleanDatabase()
+})
+
+const searchQuery = gql`
+  query($query: String!) {
+    findResources(query: $query, limit: 5) {
+      __typename
+      ... on Post {
+        id
+        title
+        content
+      }
+      ... on User {
+        id
+        slug
+        name
+      }
+    }
+  }
+`
+let user
+
+describe('resolvers', () => {
+  describe('searches', () => {
+    let variables
+
+    describe('given one user', () => {
+      beforeAll(async () => {
+        user = await Factory.build('user', {
+          id: 'a-user',
+          name: 'John Doe',
+          slug: 'john-doe',
+        })
+        authenticatedUser = await user.toJson()
+      })
+
+      const factoryOptions = {
+        authorId: 'a-user',
+      }
+
+      describe('query contains first name of user', () => {
+        it('finds the user', async () => {
+          variables = { query: 'John' }
+          await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+            data: {
+              findResources: [
+                {
+                  id: 'a-user',
+                  name: 'John Doe',
+                  slug: 'john-doe',
+                },
+              ],
+            },
+          })
+        })
+      })
+
+      describe('adding one post', () => {
+        beforeAll(async () => {
+          await Factory.build(
+            'post',
+            {
+              id: 'a-post',
+              title: 'Beitrag',
+              content: 'Ein erster Beitrag',
+            },
+            factoryOptions,
+          )
+        })
+
+        describe('query contains title of post', () => {
+          it('finds the post', async () => {
+            variables = { query: 'beitrag' }
+            await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+              data: {
+                findResources: [
+                  {
+                    __typename: 'Post',
+                    id: 'a-post',
+                    title: 'Beitrag',
+                    content: 'Ein erster Beitrag',
+                  },
+                ],
+              },
+            })
+          })
+        })
+
+        describe('casing', () => {
+          it('does not matter', async () => {
+            variables = { query: 'BEITRAG' }
+            await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+              data: {
+                findResources: [
+                  {
+                    __typename: 'Post',
+                    id: 'a-post',
+                    title: 'Beitrag',
+                    content: 'Ein erster Beitrag',
+                  },
+                ],
+              },
+            })
+          })
+        })
+
+        describe('query consists of words not present in the corpus', () => {
+          it('returns empty search results', async () => {
+            await expect(
+              query({ query: searchQuery, variables: { query: 'Unfug' } }),
+            ).resolves.toMatchObject({ data: { findResources: [] } })
+          })
+        })
+
+        describe('testing different post content', () => {
+          beforeAll(async () => {
+            return Promise.all([
+              Factory.build(
+                'post',
+                {
+                  id: 'b-post',
+                  title: 'Aufruf',
+                  content: 'Jeder sollte seinen Beitrag leisten.',
+                },
+                factoryOptions,
+              ),
+              Factory.build(
+                'post',
+                {
+                  id: 'g-post',
+                  title: 'Zusammengesetzte Wörter',
+                  content: `Ein Bindestrich kann zwischen zwei Substantiven auch dann gesetzt werden, wenn drei gleichlautende Buchstaben aufeinandertreffen. Das ist etwa bei einem „Teeei“ der Fall, das so korrekt geschrieben ist. Möglich ist hier auch die Schreibweise mit Bindestrich: Tee-Ei.`,
+                },
+                factoryOptions,
Suggested change
content: `1. binomische Formel: (a + b)² = + 2ab +
{ author: user },

{
id: 'd-post',
title: 'Der Panther',
content: `Sein Blick ist vom Vorübergehn der Stäbe
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mattwr18 Authored by mattwr18
Mar 16, 2020


Outdated (history rewrite) - original diff


@@ -0,0 +1,452 @@
+import Factory, { cleanDatabase } from '../../db/factories'
+import { gql } from '../../helpers/jest'
+import { getNeode, getDriver } from '../../db/neo4j'
+import createServer from '../../server'
+import { createTestClient } from 'apollo-server-testing'
+
+let query, authenticatedUser
+
+const driver = getDriver()
+const neode = getNeode()
+
+beforeAll(async () => {
+  await cleanDatabase()
+  const { server } = createServer({
+    context: () => {
+      return {
+        driver,
+        neode,
+        user: authenticatedUser,
+      }
+    },
+  })
+  query = createTestClient(server).query
+})
+
+afterAll(async () => {
+  await cleanDatabase()
+})
+
+const searchQuery = gql`
+  query($query: String!) {
+    findResources(query: $query, limit: 5) {
+      __typename
+      ... on Post {
+        id
+        title
+        content
+      }
+      ... on User {
+        id
+        slug
+        name
+      }
+    }
+  }
+`
+let user
+
+describe('resolvers', () => {
+  describe('searches', () => {
+    let variables
+
+    describe('given one user', () => {
+      beforeAll(async () => {
+        user = await Factory.build('user', {
+          id: 'a-user',
+          name: 'John Doe',
+          slug: 'john-doe',
+        })
+        authenticatedUser = await user.toJson()
+      })
+
+      const factoryOptions = {
+        authorId: 'a-user',
+      }
+
+      describe('query contains first name of user', () => {
+        it('finds the user', async () => {
+          variables = { query: 'John' }
+          await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+            data: {
+              findResources: [
+                {
+                  id: 'a-user',
+                  name: 'John Doe',
+                  slug: 'john-doe',
+                },
+              ],
+            },
+          })
+        })
+      })
+
+      describe('adding one post', () => {
+        beforeAll(async () => {
+          await Factory.build(
+            'post',
+            {
+              id: 'a-post',
+              title: 'Beitrag',
+              content: 'Ein erster Beitrag',
+            },
+            factoryOptions,
+          )
+        })
+
+        describe('query contains title of post', () => {
+          it('finds the post', async () => {
+            variables = { query: 'beitrag' }
+            await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+              data: {
+                findResources: [
+                  {
+                    __typename: 'Post',
+                    id: 'a-post',
+                    title: 'Beitrag',
+                    content: 'Ein erster Beitrag',
+                  },
+                ],
+              },
+            })
+          })
+        })
+
+        describe('casing', () => {
+          it('does not matter', async () => {
+            variables = { query: 'BEITRAG' }
+            await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+              data: {
+                findResources: [
+                  {
+                    __typename: 'Post',
+                    id: 'a-post',
+                    title: 'Beitrag',
+                    content: 'Ein erster Beitrag',
+                  },
+                ],
+              },
+            })
+          })
+        })
+
+        describe('query consists of words not present in the corpus', () => {
+          it('returns empty search results', async () => {
+            await expect(
+              query({ query: searchQuery, variables: { query: 'Unfug' } }),
+            ).resolves.toMatchObject({ data: { findResources: [] } })
+          })
+        })
+
+        describe('testing different post content', () => {
+          beforeAll(async () => {
+            return Promise.all([
+              Factory.build(
+                'post',
+                {
+                  id: 'b-post',
+                  title: 'Aufruf',
+                  content: 'Jeder sollte seinen Beitrag leisten.',
+                },
+                factoryOptions,
+              ),
+              Factory.build(
+                'post',
+                {
+                  id: 'g-post',
+                  title: 'Zusammengesetzte Wörter',
+                  content: `Ein Bindestrich kann zwischen zwei Substantiven auch dann gesetzt werden, wenn drei gleichlautende Buchstaben aufeinandertreffen. Das ist etwa bei einem „Teeei“ der Fall, das so korrekt geschrieben ist. Möglich ist hier auch die Schreibweise mit Bindestrich: Tee-Ei.`,
+                },
+                factoryOptions,
+              ),
+              Factory.build(
+                'post',
+                {
+                  id: 'c-post',
+                  title: 'Die binomischen Formeln',
+                  content: `1. binomische Formel: (a + b)² = a² + 2ab + b²
+2. binomische Formel: (a - b)² = a² - 2ab + b²
+3. binomische Formel: (a + b)(a - b) = a² - b²`,
+                },
+                factoryOptions,
Suggested change
content: `Sein Blick ist vom Vorübergehn der Stäbe
{ author: user },


describe('a post which content contains the title of the first post', () => {
describe('query contains the title of the first post', () => {
it('finds both posts', async () => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mattwr18 Authored by mattwr18
Mar 16, 2020


Outdated (history rewrite) - original diff


@@ -0,0 +1,452 @@
+import Factory, { cleanDatabase } from '../../db/factories'
+import { gql } from '../../helpers/jest'
+import { getNeode, getDriver } from '../../db/neo4j'
+import createServer from '../../server'
+import { createTestClient } from 'apollo-server-testing'
+
+let query, authenticatedUser
+
+const driver = getDriver()
+const neode = getNeode()
+
+beforeAll(async () => {
+  await cleanDatabase()
+  const { server } = createServer({
+    context: () => {
+      return {
+        driver,
+        neode,
+        user: authenticatedUser,
+      }
+    },
+  })
+  query = createTestClient(server).query
+})
+
+afterAll(async () => {
+  await cleanDatabase()
+})
+
+const searchQuery = gql`
+  query($query: String!) {
+    findResources(query: $query, limit: 5) {
+      __typename
+      ... on Post {
+        id
+        title
+        content
+      }
+      ... on User {
+        id
+        slug
+        name
+      }
+    }
+  }
+`
+let user
+
+describe('resolvers', () => {
+  describe('searches', () => {
+    let variables
+
+    describe('given one user', () => {
+      beforeAll(async () => {
+        user = await Factory.build('user', {
+          id: 'a-user',
+          name: 'John Doe',
+          slug: 'john-doe',
+        })
+        authenticatedUser = await user.toJson()
+      })
+
+      const factoryOptions = {
+        authorId: 'a-user',
+      }
+
+      describe('query contains first name of user', () => {
+        it('finds the user', async () => {
+          variables = { query: 'John' }
+          await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+            data: {
+              findResources: [
+                {
+                  id: 'a-user',
+                  name: 'John Doe',
+                  slug: 'john-doe',
+                },
+              ],
+            },
+          })
+        })
+      })
+
+      describe('adding one post', () => {
+        beforeAll(async () => {
+          await Factory.build(
+            'post',
+            {
+              id: 'a-post',
+              title: 'Beitrag',
+              content: 'Ein erster Beitrag',
+            },
+            factoryOptions,
+          )
+        })
+
+        describe('query contains title of post', () => {
+          it('finds the post', async () => {
+            variables = { query: 'beitrag' }
+            await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+              data: {
+                findResources: [
+                  {
+                    __typename: 'Post',
+                    id: 'a-post',
+                    title: 'Beitrag',
+                    content: 'Ein erster Beitrag',
+                  },
+                ],
+              },
+            })
+          })
+        })
+
+        describe('casing', () => {
+          it('does not matter', async () => {
+            variables = { query: 'BEITRAG' }
+            await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+              data: {
+                findResources: [
+                  {
+                    __typename: 'Post',
+                    id: 'a-post',
+                    title: 'Beitrag',
+                    content: 'Ein erster Beitrag',
+                  },
+                ],
+              },
+            })
+          })
+        })
+
+        describe('query consists of words not present in the corpus', () => {
+          it('returns empty search results', async () => {
+            await expect(
+              query({ query: searchQuery, variables: { query: 'Unfug' } }),
+            ).resolves.toMatchObject({ data: { findResources: [] } })
+          })
+        })
+
+        describe('testing different post content', () => {
+          beforeAll(async () => {
+            return Promise.all([
+              Factory.build(
+                'post',
+                {
+                  id: 'b-post',
+                  title: 'Aufruf',
+                  content: 'Jeder sollte seinen Beitrag leisten.',
+                },
+                factoryOptions,
+              ),
+              Factory.build(
+                'post',
+                {
+                  id: 'g-post',
+                  title: 'Zusammengesetzte Wörter',
+                  content: `Ein Bindestrich kann zwischen zwei Substantiven auch dann gesetzt werden, wenn drei gleichlautende Buchstaben aufeinandertreffen. Das ist etwa bei einem „Teeei“ der Fall, das so korrekt geschrieben ist. Möglich ist hier auch die Schreibweise mit Bindestrich: Tee-Ei.`,
+                },
+                factoryOptions,
+              ),
+              Factory.build(
+                'post',
+                {
+                  id: 'c-post',
+                  title: 'Die binomischen Formeln',
+                  content: `1. binomische Formel: (a + b)² = a² + 2ab + b²
+2. binomische Formel: (a - b)² = a² - 2ab + b²
+3. binomische Formel: (a + b)(a - b) = a² - b²`,
+                },
+                factoryOptions,
+              ),
+              Factory.build(
+                'post',
+                {
+                  id: 'd-post',
+                  title: 'Der Panther',
+                  content: `Sein Blick ist vom Vorübergehn der Stäbe
+so müd geworden, daß er nichts mehr hält.
+Ihm ist, als ob es tausend Stäbe gäbe
+und hinter tausend Stäben keine Welt.`,
+                },
+                factoryOptions,
Suggested change
it('finds both posts', async () => {
{ author: user },

describe('resolvers/searches', () => {
let variables

describe('given one user', () => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mattwr18 Authored by mattwr18
Mar 17, 2020


Outdated (history rewrite) - original diff


@@ -0,0 +1,452 @@
+import Factory, { cleanDatabase } from '../../db/factories'
+import { gql } from '../../helpers/jest'
+import { getNeode, getDriver } from '../../db/neo4j'
+import createServer from '../../server'
+import { createTestClient } from 'apollo-server-testing'
+
+let query, authenticatedUser
+
+const driver = getDriver()
+const neode = getNeode()
+
+beforeAll(async () => {
+  await cleanDatabase()
+  const { server } = createServer({
+    context: () => {
+      return {
+        driver,
+        neode,
+        user: authenticatedUser,
+      }
+    },
+  })
+  query = createTestClient(server).query
+})
+
+afterAll(async () => {
+  await cleanDatabase()
+})
+
+const searchQuery = gql`
+  query($query: String!) {
+    findResources(query: $query, limit: 5) {
+      __typename
+      ... on Post {
+        id
+        title
+        content
+      }
+      ... on User {
+        id
+        slug
+        name
+      }
+    }
+  }
+`
+let user
+
+describe('resolvers', () => {
+  describe('searches', () => {

why are there so many nested describe blocks? typically, I would see a nested describe block if they set up for those set of tests differs in some way from the others. it seems to me in this file that many of them are for the description only, is that right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mogge Authored by Mogge
Mar 17, 2020


Yes. This is the way @roschaefer wanted it. At least this is what I understood that he wanted

data: {
findResources: [
{
id: 'a-user',
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mattwr18 Authored by mattwr18
Mar 17, 2020


Outdated (history rewrite) - original diff


@@ -0,0 +1,452 @@
+import Factory, { cleanDatabase } from '../../db/factories'
+import { gql } from '../../helpers/jest'
+import { getNeode, getDriver } from '../../db/neo4j'
+import createServer from '../../server'
+import { createTestClient } from 'apollo-server-testing'
+
+let query, authenticatedUser
+
+const driver = getDriver()
+const neode = getNeode()
+
+beforeAll(async () => {
+  await cleanDatabase()
+  const { server } = createServer({
+    context: () => {
+      return {
+        driver,
+        neode,
+        user: authenticatedUser,
+      }
+    },
+  })
+  query = createTestClient(server).query
+})
+
+afterAll(async () => {
+  await cleanDatabase()
+})
+
+const searchQuery = gql`
+  query($query: String!) {
+    findResources(query: $query, limit: 5) {
+      __typename
+      ... on Post {
+        id
+        title
+        content
+      }
+      ... on User {
+        id
+        slug
+        name
+      }
+    }
+  }
+`
+let user
+
+describe('resolvers', () => {
+  describe('searches', () => {
+    let variables
+
+    describe('given one user', () => {
+      beforeAll(async () => {
+        user = await Factory.build('user', {
+          id: 'a-user',
+          name: 'John Doe',
+          slug: 'john-doe',
+        })
+        authenticatedUser = await user.toJson()
+      })
+
+      const factoryOptions = {
+        authorId: 'a-user',
+      }
+
+      describe('query contains first name of user', () => {

here for example...

'post',
{
id: 'b-post',
title: 'Aufruf',
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mattwr18 Authored by mattwr18
Mar 17, 2020


Outdated (history rewrite) - original diff


@@ -0,0 +1,452 @@
+import Factory, { cleanDatabase } from '../../db/factories'
+import { gql } from '../../helpers/jest'
+import { getNeode, getDriver } from '../../db/neo4j'
+import createServer from '../../server'
+import { createTestClient } from 'apollo-server-testing'
+
+let query, authenticatedUser
+
+const driver = getDriver()
+const neode = getNeode()
+
+beforeAll(async () => {
+  await cleanDatabase()
+  const { server } = createServer({
+    context: () => {
+      return {
+        driver,
+        neode,
+        user: authenticatedUser,
+      }
+    },
+  })
+  query = createTestClient(server).query
+})
+
+afterAll(async () => {
+  await cleanDatabase()
+})
+
+const searchQuery = gql`
+  query($query: String!) {
+    findResources(query: $query, limit: 5) {
+      __typename
+      ... on Post {
+        id
+        title
+        content
+      }
+      ... on User {
+        id
+        slug
+        name
+      }
+    }
+  }
+`
+let user
+
+describe('resolvers', () => {
+  describe('searches', () => {
+    let variables
+
+    describe('given one user', () => {
+      beforeAll(async () => {
+        user = await Factory.build('user', {
+          id: 'a-user',
+          name: 'John Doe',
+          slug: 'john-doe',
+        })
+        authenticatedUser = await user.toJson()
+      })
+
+      const factoryOptions = {
+        authorId: 'a-user',
+      }
+
+      describe('query contains first name of user', () => {
+        it('finds the user', async () => {
+          variables = { query: 'John' }
+          await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+            data: {
+              findResources: [
+                {
+                  id: 'a-user',
+                  name: 'John Doe',
+                  slug: 'john-doe',
+                },
+              ],
+            },
+          })
+        })
+      })
+
+      describe('adding one post', () => {
+        beforeAll(async () => {
+          await Factory.build(
+            'post',
+            {
+              id: 'a-post',
+              title: 'Beitrag',
+              content: 'Ein erster Beitrag',
+            },
+            factoryOptions,
+          )
+        })
+
+        describe('query contains title of post', () => {
+          it('finds the post', async () => {
+            variables = { query: 'beitrag' }
+            await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+              data: {
+                findResources: [
+                  {
+                    __typename: 'Post',
+                    id: 'a-post',
+                    title: 'Beitrag',
+                    content: 'Ein erster Beitrag',
+                  },
+                ],
+              },
+            })
+          })
+        })
+
+        describe('casing', () => {
+          it('does not matter', async () => {
+            variables = { query: 'BEITRAG' }
+            await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+              data: {
+                findResources: [
+                  {
+                    __typename: 'Post',
+                    id: 'a-post',
+                    title: 'Beitrag',
+                    content: 'Ein erster Beitrag',
+                  },
+                ],
+              },
+            })
+          })
+        })
+
+        describe('query consists of words not present in the corpus', () => {
+          it('returns empty search results', async () => {
+            await expect(
+              query({ query: searchQuery, variables: { query: 'Unfug' } }),
+            ).resolves.toMatchObject({ data: { findResources: [] } })
+          })
+        })
+
+        describe('testing different post content', () => {

this is a good use of a describe block, since the set up is different. Although, it's not immediately clear to me why these posts could be created in a up the stream describe block and then tested in it blocks further down...
maybe you wanted to have the build closer to the test to make it easier to see the specifics of each post?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mogge Authored by Mogge
Mar 17, 2020


I need async calls to the factory. describe cannot be used async. This would leed to a beforeAll call before each new test and therefore a even deeper nesting of describe blocks. So I decided to write all the data to the DB firsrt, and then explain each test case later.

data: {
findResources: expect.arrayContaining([
{
__typename: 'Post',
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mattwr18 Authored by mattwr18
Mar 17, 2020


Outdated (history rewrite) - original diff


@@ -0,0 +1,452 @@
+import Factory, { cleanDatabase } from '../../db/factories'
+import { gql } from '../../helpers/jest'
+import { getNeode, getDriver } from '../../db/neo4j'
+import createServer from '../../server'
+import { createTestClient } from 'apollo-server-testing'
+
+let query, authenticatedUser
+
+const driver = getDriver()
+const neode = getNeode()
+
+beforeAll(async () => {
+  await cleanDatabase()
+  const { server } = createServer({
+    context: () => {
+      return {
+        driver,
+        neode,
+        user: authenticatedUser,
+      }
+    },
+  })
+  query = createTestClient(server).query
+})
+
+afterAll(async () => {
+  await cleanDatabase()
+})
+
+const searchQuery = gql`
+  query($query: String!) {
+    findResources(query: $query, limit: 5) {
+      __typename
+      ... on Post {
+        id
+        title
+        content
+      }
+      ... on User {
+        id
+        slug
+        name
+      }
+    }
+  }
+`
+let user
+
+describe('resolvers', () => {
+  describe('searches', () => {
+    let variables
+
+    describe('given one user', () => {
+      beforeAll(async () => {
+        user = await Factory.build('user', {
+          id: 'a-user',
+          name: 'John Doe',
+          slug: 'john-doe',
+        })
+        authenticatedUser = await user.toJson()
+      })
+
+      const factoryOptions = {
+        authorId: 'a-user',
+      }
+
+      describe('query contains first name of user', () => {
+        it('finds the user', async () => {
+          variables = { query: 'John' }
+          await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+            data: {
+              findResources: [
+                {
+                  id: 'a-user',
+                  name: 'John Doe',
+                  slug: 'john-doe',
+                },
+              ],
+            },
+          })
+        })
+      })
+
+      describe('adding one post', () => {
+        beforeAll(async () => {
+          await Factory.build(
+            'post',
+            {
+              id: 'a-post',
+              title: 'Beitrag',
+              content: 'Ein erster Beitrag',
+            },
+            factoryOptions,
+          )
+        })
+
+        describe('query contains title of post', () => {
+          it('finds the post', async () => {
+            variables = { query: 'beitrag' }
+            await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+              data: {
+                findResources: [
+                  {
+                    __typename: 'Post',
+                    id: 'a-post',
+                    title: 'Beitrag',
+                    content: 'Ein erster Beitrag',
+                  },
+                ],
+              },
+            })
+          })
+        })
+
+        describe('casing', () => {
+          it('does not matter', async () => {
+            variables = { query: 'BEITRAG' }
+            await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+              data: {
+                findResources: [
+                  {
+                    __typename: 'Post',
+                    id: 'a-post',
+                    title: 'Beitrag',
+                    content: 'Ein erster Beitrag',
+                  },
+                ],
+              },
+            })
+          })
+        })
+
+        describe('query consists of words not present in the corpus', () => {
+          it('returns empty search results', async () => {
+            await expect(
+              query({ query: searchQuery, variables: { query: 'Unfug' } }),
+            ).resolves.toMatchObject({ data: { findResources: [] } })
+          })
+        })
+
+        describe('testing different post content', () => {
+          beforeAll(async () => {
+            return Promise.all([
+              Factory.build(
+                'post',
+                {
+                  id: 'b-post',
+                  title: 'Aufruf',
+                  content: 'Jeder sollte seinen Beitrag leisten.',
+                },
+                factoryOptions,
+              ),
+              Factory.build(
+                'post',
+                {
+                  id: 'g-post',
+                  title: 'Zusammengesetzte Wörter',
+                  content: `Ein Bindestrich kann zwischen zwei Substantiven auch dann gesetzt werden, wenn drei gleichlautende Buchstaben aufeinandertreffen. Das ist etwa bei einem „Teeei“ der Fall, das so korrekt geschrieben ist. Möglich ist hier auch die Schreibweise mit Bindestrich: Tee-Ei.`,
+                },
+                factoryOptions,
+              ),
+              Factory.build(
+                'post',
+                {
+                  id: 'c-post',
+                  title: 'Die binomischen Formeln',
+                  content: `1. binomische Formel: (a + b)² = a² + 2ab + b²
+2. binomische Formel: (a - b)² = a² - 2ab + b²
+3. binomische Formel: (a + b)(a - b) = a² - b²`,
+                },
+                factoryOptions,
+              ),
+              Factory.build(
+                'post',
+                {
+                  id: 'd-post',
+                  title: 'Der Panther',
+                  content: `Sein Blick ist vom Vorübergehn der Stäbe
+so müd geworden, daß er nichts mehr hält.
+Ihm ist, als ob es tausend Stäbe gäbe
+und hinter tausend Stäben keine Welt.`,
+                },
+                factoryOptions,
+              ),
+            ])
+          })
+
+          describe('a post which content contains the title of the first post', () => {
+            describe('query contains the title of the first post', () => {

same as 👆

},
})
})
})
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mattwr18 Authored by mattwr18
Mar 17, 2020


Outdated (history rewrite) - original diff


@@ -0,0 +1,452 @@
+import Factory, { cleanDatabase } from '../../db/factories'
+import { gql } from '../../helpers/jest'
+import { getNeode, getDriver } from '../../db/neo4j'
+import createServer from '../../server'
+import { createTestClient } from 'apollo-server-testing'
+
+let query, authenticatedUser
+
+const driver = getDriver()
+const neode = getNeode()
+
+beforeAll(async () => {
+  await cleanDatabase()
+  const { server } = createServer({
+    context: () => {
+      return {
+        driver,
+        neode,
+        user: authenticatedUser,
+      }
+    },
+  })
+  query = createTestClient(server).query
+})
+
+afterAll(async () => {
+  await cleanDatabase()
+})
+
+const searchQuery = gql`
+  query($query: String!) {
+    findResources(query: $query, limit: 5) {
+      __typename
+      ... on Post {
+        id
+        title
+        content
+      }
+      ... on User {
+        id
+        slug
+        name
+      }
+    }
+  }
+`
+let user
+
+describe('resolvers', () => {
+  describe('searches', () => {
+    let variables
+
+    describe('given one user', () => {
+      beforeAll(async () => {
+        user = await Factory.build('user', {
+          id: 'a-user',
+          name: 'John Doe',
+          slug: 'john-doe',
+        })
+        authenticatedUser = await user.toJson()
+      })
+
+      const factoryOptions = {
+        authorId: 'a-user',
+      }
+
+      describe('query contains first name of user', () => {
+        it('finds the user', async () => {
+          variables = { query: 'John' }
+          await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+            data: {
+              findResources: [
+                {
+                  id: 'a-user',
+                  name: 'John Doe',
+                  slug: 'john-doe',
+                },
+              ],
+            },
+          })
+        })
+      })
+
+      describe('adding one post', () => {
+        beforeAll(async () => {
+          await Factory.build(
+            'post',
+            {
+              id: 'a-post',
+              title: 'Beitrag',
+              content: 'Ein erster Beitrag',
+            },
+            factoryOptions,
+          )
+        })
+
+        describe('query contains title of post', () => {
+          it('finds the post', async () => {
+            variables = { query: 'beitrag' }
+            await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+              data: {
+                findResources: [
+                  {
+                    __typename: 'Post',
+                    id: 'a-post',
+                    title: 'Beitrag',
+                    content: 'Ein erster Beitrag',
+                  },
+                ],
+              },
+            })
+          })
+        })
+
+        describe('casing', () => {
+          it('does not matter', async () => {
+            variables = { query: 'BEITRAG' }
+            await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+              data: {
+                findResources: [
+                  {
+                    __typename: 'Post',
+                    id: 'a-post',
+                    title: 'Beitrag',
+                    content: 'Ein erster Beitrag',
+                  },
+                ],
+              },
+            })
+          })
+        })
+
+        describe('query consists of words not present in the corpus', () => {
+          it('returns empty search results', async () => {
+            await expect(
+              query({ query: searchQuery, variables: { query: 'Unfug' } }),
+            ).resolves.toMatchObject({ data: { findResources: [] } })
+          })
+        })
+
+        describe('testing different post content', () => {
+          beforeAll(async () => {
+            return Promise.all([
+              Factory.build(
+                'post',
+                {
+                  id: 'b-post',
+                  title: 'Aufruf',
+                  content: 'Jeder sollte seinen Beitrag leisten.',
+                },
+                factoryOptions,
+              ),
+              Factory.build(
+                'post',
+                {
+                  id: 'g-post',
+                  title: 'Zusammengesetzte Wörter',
+                  content: `Ein Bindestrich kann zwischen zwei Substantiven auch dann gesetzt werden, wenn drei gleichlautende Buchstaben aufeinandertreffen. Das ist etwa bei einem „Teeei“ der Fall, das so korrekt geschrieben ist. Möglich ist hier auch die Schreibweise mit Bindestrich: Tee-Ei.`,
+                },
+                factoryOptions,
+              ),
+              Factory.build(
+                'post',
+                {
+                  id: 'c-post',
+                  title: 'Die binomischen Formeln',
+                  content: `1. binomische Formel: (a + b)² = a² + 2ab + b²
+2. binomische Formel: (a - b)² = a² - 2ab + b²
+3. binomische Formel: (a + b)(a - b) = a² - b²`,
+                },
+                factoryOptions,
+              ),
+              Factory.build(
+                'post',
+                {
+                  id: 'd-post',
+                  title: 'Der Panther',
+                  content: `Sein Blick ist vom Vorübergehn der Stäbe
+so müd geworden, daß er nichts mehr hält.
+Ihm ist, als ob es tausend Stäbe gäbe
+und hinter tausend Stäben keine Welt.`,
+                },
+                factoryOptions,
+              ),
+            ])
+          })
+
+          describe('a post which content contains the title of the first post', () => {
+            describe('query contains the title of the first post', () => {
+              it('finds both posts', async () => {
+                variables = { query: 'beitrag' }
+                await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+                  data: {
+                    findResources: expect.arrayContaining([
+                      {
+                        __typename: 'Post',
+                        id: 'a-post',
+                        title: 'Beitrag',
+                        content: 'Ein erster Beitrag',
+                      },
+                      {
+                        __typename: 'Post',
+                        id: 'b-post',
+                        title: 'Aufruf',
+                        content: 'Jeder sollte seinen Beitrag leisten.',
+                      },
+                    ]),
+                  },
+                })
+              })
+            })
+          })
+
+          describe('a post that contains a hyphen between two words and German quotation marks', () => {
+            describe('hyphens in query', () => {
+              it('will be treated as ordinary characters', async () => {
+                variables = { query: 'tee-ei' }
+                await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+                  data: {
+                    findResources: [
+                      {
+                        __typename: 'Post',
+                        id: 'g-post',
+                        title: 'Zusammengesetzte Wörter',
+                        content: `Ein Bindestrich kann zwischen zwei Substantiven auch dann gesetzt werden, wenn drei gleichlautende Buchstaben aufeinandertreffen. Das ist etwa bei einem „Teeei“ der Fall, das so korrekt geschrieben ist. Möglich ist hier auch die Schreibweise mit Bindestrich: Tee-Ei.`,
+                      },
+                    ],
+                  },
+                })
+              })
+            })
+
+            describe('German quotation marks in query', () => {
+              it('will be treated as ordinary characters', async () => {
+                variables = { query: '„teeei“' }
+                await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+                  data: {
+                    findResources: [
+                      {
+                        __typename: 'Post',
+                        id: 'g-post',
+                        title: 'Zusammengesetzte Wörter',
+                        content: `Ein Bindestrich kann zwischen zwei Substantiven auch dann gesetzt werden, wenn drei gleichlautende Buchstaben aufeinandertreffen. Das ist etwa bei einem „Teeei“ der Fall, das so korrekt geschrieben ist. Möglich ist hier auch die Schreibweise mit Bindestrich: Tee-Ei.`,
+                      },
+                    ],
+                  },
+                })
+              })
+            })
+          })

I'm confused by these two test cases... is there some docs you can link to that explain why this was an issue in the past?
I went to the link you provided https://lucene.apache.org/core/8_3_1/queryparser/org/apache/lucene/queryparser/classic/package-summary.html#Escaping_Special_Characters , but I'm not sure where the German quotation marks fit into the equation.

Also looking at the tests, it's not clear. The first test searches for tee-ei, which the content does contain, so I would expect it to appear in the list, but maybe it wasn't because of the German quotations, somehow?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mogge Authored by Mogge
Mar 17, 2020


The quotation marks are a testcase for unicode chars. I will put that in the description.

await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
data: {
findResources: [
{
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mattwr18 Authored by mattwr18
Mar 17, 2020


Outdated (history rewrite) - original diff


@@ -0,0 +1,452 @@
+import Factory, { cleanDatabase } from '../../db/factories'
+import { gql } from '../../helpers/jest'
+import { getNeode, getDriver } from '../../db/neo4j'
+import createServer from '../../server'
+import { createTestClient } from 'apollo-server-testing'
+
+let query, authenticatedUser
+
+const driver = getDriver()
+const neode = getNeode()
+
+beforeAll(async () => {
+  await cleanDatabase()
+  const { server } = createServer({
+    context: () => {
+      return {
+        driver,
+        neode,
+        user: authenticatedUser,
+      }
+    },
+  })
+  query = createTestClient(server).query
+})
+
+afterAll(async () => {
+  await cleanDatabase()
+})
+
+const searchQuery = gql`
+  query($query: String!) {
+    findResources(query: $query, limit: 5) {
+      __typename
+      ... on Post {
+        id
+        title
+        content
+      }
+      ... on User {
+        id
+        slug
+        name
+      }
+    }
+  }
+`
+let user
+
+describe('resolvers', () => {
+  describe('searches', () => {
+    let variables
+
+    describe('given one user', () => {
+      beforeAll(async () => {
+        user = await Factory.build('user', {
+          id: 'a-user',
+          name: 'John Doe',
+          slug: 'john-doe',
+        })
+        authenticatedUser = await user.toJson()
+      })
+
+      const factoryOptions = {
+        authorId: 'a-user',
+      }
+
+      describe('query contains first name of user', () => {
+        it('finds the user', async () => {
+          variables = { query: 'John' }
+          await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+            data: {
+              findResources: [
+                {
+                  id: 'a-user',
+                  name: 'John Doe',
+                  slug: 'john-doe',
+                },
+              ],
+            },
+          })
+        })
+      })
+
+      describe('adding one post', () => {
+        beforeAll(async () => {
+          await Factory.build(
+            'post',
+            {
+              id: 'a-post',
+              title: 'Beitrag',
+              content: 'Ein erster Beitrag',
+            },
+            factoryOptions,
+          )
+        })
+
+        describe('query contains title of post', () => {
+          it('finds the post', async () => {
+            variables = { query: 'beitrag' }
+            await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+              data: {
+                findResources: [
+                  {
+                    __typename: 'Post',
+                    id: 'a-post',
+                    title: 'Beitrag',
+                    content: 'Ein erster Beitrag',
+                  },
+                ],
+              },
+            })
+          })
+        })
+
+        describe('casing', () => {
+          it('does not matter', async () => {
+            variables = { query: 'BEITRAG' }
+            await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+              data: {
+                findResources: [
+                  {
+                    __typename: 'Post',
+                    id: 'a-post',
+                    title: 'Beitrag',
+                    content: 'Ein erster Beitrag',
+                  },
+                ],
+              },
+            })
+          })
+        })
+
+        describe('query consists of words not present in the corpus', () => {
+          it('returns empty search results', async () => {
+            await expect(
+              query({ query: searchQuery, variables: { query: 'Unfug' } }),
+            ).resolves.toMatchObject({ data: { findResources: [] } })
+          })
+        })
+
+        describe('testing different post content', () => {
+          beforeAll(async () => {
+            return Promise.all([
+              Factory.build(
+                'post',
+                {
+                  id: 'b-post',
+                  title: 'Aufruf',
+                  content: 'Jeder sollte seinen Beitrag leisten.',
+                },
+                factoryOptions,
+              ),
+              Factory.build(
+                'post',
+                {
+                  id: 'g-post',
+                  title: 'Zusammengesetzte Wörter',
+                  content: `Ein Bindestrich kann zwischen zwei Substantiven auch dann gesetzt werden, wenn drei gleichlautende Buchstaben aufeinandertreffen. Das ist etwa bei einem „Teeei“ der Fall, das so korrekt geschrieben ist. Möglich ist hier auch die Schreibweise mit Bindestrich: Tee-Ei.`,
+                },
+                factoryOptions,
+              ),
+              Factory.build(
+                'post',
+                {
+                  id: 'c-post',
+                  title: 'Die binomischen Formeln',
+                  content: `1. binomische Formel: (a + b)² = a² + 2ab + b²
+2. binomische Formel: (a - b)² = a² - 2ab + b²
+3. binomische Formel: (a + b)(a - b) = a² - b²`,
+                },
+                factoryOptions,
+              ),
+              Factory.build(
+                'post',
+                {
+                  id: 'd-post',
+                  title: 'Der Panther',
+                  content: `Sein Blick ist vom Vorübergehn der Stäbe
+so müd geworden, daß er nichts mehr hält.
+Ihm ist, als ob es tausend Stäbe gäbe
+und hinter tausend Stäben keine Welt.`,
+                },
+                factoryOptions,
+              ),
+            ])
+          })
+
+          describe('a post which content contains the title of the first post', () => {
+            describe('query contains the title of the first post', () => {
+              it('finds both posts', async () => {
+                variables = { query: 'beitrag' }
+                await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+                  data: {
+                    findResources: expect.arrayContaining([
+                      {
+                        __typename: 'Post',
+                        id: 'a-post',
+                        title: 'Beitrag',
+                        content: 'Ein erster Beitrag',
+                      },
+                      {
+                        __typename: 'Post',
+                        id: 'b-post',
+                        title: 'Aufruf',
+                        content: 'Jeder sollte seinen Beitrag leisten.',
+                      },
+                    ]),
+                  },
+                })
+              })
+            })
+          })
+
+          describe('a post that contains a hyphen between two words and German quotation marks', () => {
+            describe('hyphens in query', () => {
+              it('will be treated as ordinary characters', async () => {
+                variables = { query: 'tee-ei' }
+                await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+                  data: {
+                    findResources: [
+                      {
+                        __typename: 'Post',
+                        id: 'g-post',
+                        title: 'Zusammengesetzte Wörter',
+                        content: `Ein Bindestrich kann zwischen zwei Substantiven auch dann gesetzt werden, wenn drei gleichlautende Buchstaben aufeinandertreffen. Das ist etwa bei einem „Teeei“ der Fall, das so korrekt geschrieben ist. Möglich ist hier auch die Schreibweise mit Bindestrich: Tee-Ei.`,
+                      },
+                    ],
+                  },
+                })
+              })
+            })
+
+            describe('German quotation marks in query', () => {
+              it('will be treated as ordinary characters', async () => {
+                variables = { query: '„teeei“' }
+                await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+                  data: {
+                    findResources: [
+                      {
+                        __typename: 'Post',
+                        id: 'g-post',
+                        title: 'Zusammengesetzte Wörter',
+                        content: `Ein Bindestrich kann zwischen zwei Substantiven auch dann gesetzt werden, wenn drei gleichlautende Buchstaben aufeinandertreffen. Das ist etwa bei einem „Teeei“ der Fall, das so korrekt geschrieben ist. Möglich ist hier auch die Schreibweise mit Bindestrich: Tee-Ei.`,
+                      },
+                    ],
+                  },
+                })
+              })
+            })
+          })
+
+          describe('a post that contains a simple mathematical exprssion and linebreaks', () => {
Suggested change
{
describe('a post that contains a simple mathematical expression and line breaks', () => {

data: {
findResources: [
{
__typename: 'Post',
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mattwr18 Authored by mattwr18
Mar 17, 2020


Outdated (history rewrite) - original diff


@@ -0,0 +1,452 @@
+import Factory, { cleanDatabase } from '../../db/factories'
+import { gql } from '../../helpers/jest'
+import { getNeode, getDriver } from '../../db/neo4j'
+import createServer from '../../server'
+import { createTestClient } from 'apollo-server-testing'
+
+let query, authenticatedUser
+
+const driver = getDriver()
+const neode = getNeode()
+
+beforeAll(async () => {
+  await cleanDatabase()
+  const { server } = createServer({
+    context: () => {
+      return {
+        driver,
+        neode,
+        user: authenticatedUser,
+      }
+    },
+  })
+  query = createTestClient(server).query
+})
+
+afterAll(async () => {
+  await cleanDatabase()
+})
+
+const searchQuery = gql`
+  query($query: String!) {
+    findResources(query: $query, limit: 5) {
+      __typename
+      ... on Post {
+        id
+        title
+        content
+      }
+      ... on User {
+        id
+        slug
+        name
+      }
+    }
+  }
+`
+let user
+
+describe('resolvers', () => {
+  describe('searches', () => {
+    let variables
+
+    describe('given one user', () => {
+      beforeAll(async () => {
+        user = await Factory.build('user', {
+          id: 'a-user',
+          name: 'John Doe',
+          slug: 'john-doe',
+        })
+        authenticatedUser = await user.toJson()
+      })
+
+      const factoryOptions = {
+        authorId: 'a-user',
+      }
+
+      describe('query contains first name of user', () => {
+        it('finds the user', async () => {
+          variables = { query: 'John' }
+          await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+            data: {
+              findResources: [
+                {
+                  id: 'a-user',
+                  name: 'John Doe',
+                  slug: 'john-doe',
+                },
+              ],
+            },
+          })
+        })
+      })
+
+      describe('adding one post', () => {
+        beforeAll(async () => {
+          await Factory.build(
+            'post',
+            {
+              id: 'a-post',
+              title: 'Beitrag',
+              content: 'Ein erster Beitrag',
+            },
+            factoryOptions,
+          )
+        })
+
+        describe('query contains title of post', () => {
+          it('finds the post', async () => {
+            variables = { query: 'beitrag' }
+            await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+              data: {
+                findResources: [
+                  {
+                    __typename: 'Post',
+                    id: 'a-post',
+                    title: 'Beitrag',
+                    content: 'Ein erster Beitrag',
+                  },
+                ],
+              },
+            })
+          })
+        })
+
+        describe('casing', () => {
+          it('does not matter', async () => {
+            variables = { query: 'BEITRAG' }
+            await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+              data: {
+                findResources: [
+                  {
+                    __typename: 'Post',
+                    id: 'a-post',
+                    title: 'Beitrag',
+                    content: 'Ein erster Beitrag',
+                  },
+                ],
+              },
+            })
+          })
+        })
+
+        describe('query consists of words not present in the corpus', () => {
+          it('returns empty search results', async () => {
+            await expect(
+              query({ query: searchQuery, variables: { query: 'Unfug' } }),
+            ).resolves.toMatchObject({ data: { findResources: [] } })
+          })
+        })
+
+        describe('testing different post content', () => {
+          beforeAll(async () => {
+            return Promise.all([
+              Factory.build(
+                'post',
+                {
+                  id: 'b-post',
+                  title: 'Aufruf',
+                  content: 'Jeder sollte seinen Beitrag leisten.',
+                },
+                factoryOptions,
+              ),
+              Factory.build(
+                'post',
+                {
+                  id: 'g-post',
+                  title: 'Zusammengesetzte Wörter',
+                  content: `Ein Bindestrich kann zwischen zwei Substantiven auch dann gesetzt werden, wenn drei gleichlautende Buchstaben aufeinandertreffen. Das ist etwa bei einem „Teeei“ der Fall, das so korrekt geschrieben ist. Möglich ist hier auch die Schreibweise mit Bindestrich: Tee-Ei.`,
+                },
+                factoryOptions,
+              ),
+              Factory.build(
+                'post',
+                {
+                  id: 'c-post',
+                  title: 'Die binomischen Formeln',
+                  content: `1. binomische Formel: (a + b)² = a² + 2ab + b²
+2. binomische Formel: (a - b)² = a² - 2ab + b²
+3. binomische Formel: (a + b)(a - b) = a² - b²`,
+                },
+                factoryOptions,
+              ),
+              Factory.build(
+                'post',
+                {
+                  id: 'd-post',
+                  title: 'Der Panther',
+                  content: `Sein Blick ist vom Vorübergehn der Stäbe
+so müd geworden, daß er nichts mehr hält.
+Ihm ist, als ob es tausend Stäbe gäbe
+und hinter tausend Stäben keine Welt.`,
+                },
+                factoryOptions,
+              ),
+            ])
+          })
+
+          describe('a post which content contains the title of the first post', () => {
+            describe('query contains the title of the first post', () => {
+              it('finds both posts', async () => {
+                variables = { query: 'beitrag' }
+                await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+                  data: {
+                    findResources: expect.arrayContaining([
+                      {
+                        __typename: 'Post',
+                        id: 'a-post',
+                        title: 'Beitrag',
+                        content: 'Ein erster Beitrag',
+                      },
+                      {
+                        __typename: 'Post',
+                        id: 'b-post',
+                        title: 'Aufruf',
+                        content: 'Jeder sollte seinen Beitrag leisten.',
+                      },
+                    ]),
+                  },
+                })
+              })
+            })
+          })
+
+          describe('a post that contains a hyphen between two words and German quotation marks', () => {
+            describe('hyphens in query', () => {
+              it('will be treated as ordinary characters', async () => {
+                variables = { query: 'tee-ei' }
+                await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+                  data: {
+                    findResources: [
+                      {
+                        __typename: 'Post',
+                        id: 'g-post',
+                        title: 'Zusammengesetzte Wörter',
+                        content: `Ein Bindestrich kann zwischen zwei Substantiven auch dann gesetzt werden, wenn drei gleichlautende Buchstaben aufeinandertreffen. Das ist etwa bei einem „Teeei“ der Fall, das so korrekt geschrieben ist. Möglich ist hier auch die Schreibweise mit Bindestrich: Tee-Ei.`,
+                      },
+                    ],
+                  },
+                })
+              })
+            })
+
+            describe('German quotation marks in query', () => {
+              it('will be treated as ordinary characters', async () => {
+                variables = { query: '„teeei“' }
+                await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+                  data: {
+                    findResources: [
+                      {
+                        __typename: 'Post',
+                        id: 'g-post',
+                        title: 'Zusammengesetzte Wörter',
+                        content: `Ein Bindestrich kann zwischen zwei Substantiven auch dann gesetzt werden, wenn drei gleichlautende Buchstaben aufeinandertreffen. Das ist etwa bei einem „Teeei“ der Fall, das so korrekt geschrieben ist. Möglich ist hier auch die Schreibweise mit Bindestrich: Tee-Ei.`,
+                      },
+                    ],
+                  },
+                })
+              })
+            })
+          })
+
+          describe('a post that contains a simple mathematical exprssion and linebreaks', () => {
+            describe('query a part of the mathematical expression', () => {

this is cool, and seeing the docs, I can see how this is possible. I wonder if this is an actual use case, but I guess it doesn't hurt to have a test case for it?

await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
data: {
findResources: [
{
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mattwr18 Authored by mattwr18
Mar 17, 2020


Outdated (history rewrite) - original diff


@@ -0,0 +1,452 @@
+import Factory, { cleanDatabase } from '../../db/factories'
+import { gql } from '../../helpers/jest'
+import { getNeode, getDriver } from '../../db/neo4j'
+import createServer from '../../server'
+import { createTestClient } from 'apollo-server-testing'
+
+let query, authenticatedUser
+
+const driver = getDriver()
+const neode = getNeode()
+
+beforeAll(async () => {
+  await cleanDatabase()
+  const { server } = createServer({
+    context: () => {
+      return {
+        driver,
+        neode,
+        user: authenticatedUser,
+      }
+    },
+  })
+  query = createTestClient(server).query
+})
+
+afterAll(async () => {
+  await cleanDatabase()
+})
+
+const searchQuery = gql`
+  query($query: String!) {
+    findResources(query: $query, limit: 5) {
+      __typename
+      ... on Post {
+        id
+        title
+        content
+      }
+      ... on User {
+        id
+        slug
+        name
+      }
+    }
+  }
+`
+let user
+
+describe('resolvers', () => {
+  describe('searches', () => {
+    let variables
+
+    describe('given one user', () => {
+      beforeAll(async () => {
+        user = await Factory.build('user', {
+          id: 'a-user',
+          name: 'John Doe',
+          slug: 'john-doe',
+        })
+        authenticatedUser = await user.toJson()
+      })
+
+      const factoryOptions = {
+        authorId: 'a-user',
+      }
+
+      describe('query contains first name of user', () => {
+        it('finds the user', async () => {
+          variables = { query: 'John' }
+          await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+            data: {
+              findResources: [
+                {
+                  id: 'a-user',
+                  name: 'John Doe',
+                  slug: 'john-doe',
+                },
+              ],
+            },
+          })
+        })
+      })
+
+      describe('adding one post', () => {
+        beforeAll(async () => {
+          await Factory.build(
+            'post',
+            {
+              id: 'a-post',
+              title: 'Beitrag',
+              content: 'Ein erster Beitrag',
+            },
+            factoryOptions,
+          )
+        })
+
+        describe('query contains title of post', () => {
+          it('finds the post', async () => {
+            variables = { query: 'beitrag' }
+            await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+              data: {
+                findResources: [
+                  {
+                    __typename: 'Post',
+                    id: 'a-post',
+                    title: 'Beitrag',
+                    content: 'Ein erster Beitrag',
+                  },
+                ],
+              },
+            })
+          })
+        })
+
+        describe('casing', () => {
+          it('does not matter', async () => {
+            variables = { query: 'BEITRAG' }
+            await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+              data: {
+                findResources: [
+                  {
+                    __typename: 'Post',
+                    id: 'a-post',
+                    title: 'Beitrag',
+                    content: 'Ein erster Beitrag',
+                  },
+                ],
+              },
+            })
+          })
+        })
+
+        describe('query consists of words not present in the corpus', () => {
+          it('returns empty search results', async () => {
+            await expect(
+              query({ query: searchQuery, variables: { query: 'Unfug' } }),
+            ).resolves.toMatchObject({ data: { findResources: [] } })
+          })
+        })
+
+        describe('testing different post content', () => {
+          beforeAll(async () => {
+            return Promise.all([
+              Factory.build(
+                'post',
+                {
+                  id: 'b-post',
+                  title: 'Aufruf',
+                  content: 'Jeder sollte seinen Beitrag leisten.',
+                },
+                factoryOptions,
+              ),
+              Factory.build(
+                'post',
+                {
+                  id: 'g-post',
+                  title: 'Zusammengesetzte Wörter',
+                  content: `Ein Bindestrich kann zwischen zwei Substantiven auch dann gesetzt werden, wenn drei gleichlautende Buchstaben aufeinandertreffen. Das ist etwa bei einem „Teeei“ der Fall, das so korrekt geschrieben ist. Möglich ist hier auch die Schreibweise mit Bindestrich: Tee-Ei.`,
+                },
+                factoryOptions,
+              ),
+              Factory.build(
+                'post',
+                {
+                  id: 'c-post',
+                  title: 'Die binomischen Formeln',
+                  content: `1. binomische Formel: (a + b)² = a² + 2ab + b²
+2. binomische Formel: (a - b)² = a² - 2ab + b²
+3. binomische Formel: (a + b)(a - b) = a² - b²`,
+                },
+                factoryOptions,
+              ),
+              Factory.build(
+                'post',
+                {
+                  id: 'd-post',
+                  title: 'Der Panther',
+                  content: `Sein Blick ist vom Vorübergehn der Stäbe
+so müd geworden, daß er nichts mehr hält.
+Ihm ist, als ob es tausend Stäbe gäbe
+und hinter tausend Stäben keine Welt.`,
+                },
+                factoryOptions,
+              ),
+            ])
+          })
+
+          describe('a post which content contains the title of the first post', () => {
+            describe('query contains the title of the first post', () => {
+              it('finds both posts', async () => {
+                variables = { query: 'beitrag' }
+                await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+                  data: {
+                    findResources: expect.arrayContaining([
+                      {
+                        __typename: 'Post',
+                        id: 'a-post',
+                        title: 'Beitrag',
+                        content: 'Ein erster Beitrag',
+                      },
+                      {
+                        __typename: 'Post',
+                        id: 'b-post',
+                        title: 'Aufruf',
+                        content: 'Jeder sollte seinen Beitrag leisten.',
+                      },
+                    ]),
+                  },
+                })
+              })
+            })
+          })
+
+          describe('a post that contains a hyphen between two words and German quotation marks', () => {
+            describe('hyphens in query', () => {
+              it('will be treated as ordinary characters', async () => {
+                variables = { query: 'tee-ei' }
+                await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+                  data: {
+                    findResources: [
+                      {
+                        __typename: 'Post',
+                        id: 'g-post',
+                        title: 'Zusammengesetzte Wörter',
+                        content: `Ein Bindestrich kann zwischen zwei Substantiven auch dann gesetzt werden, wenn drei gleichlautende Buchstaben aufeinandertreffen. Das ist etwa bei einem „Teeei“ der Fall, das so korrekt geschrieben ist. Möglich ist hier auch die Schreibweise mit Bindestrich: Tee-Ei.`,
+                      },
+                    ],
+                  },
+                })
+              })
+            })
+
+            describe('German quotation marks in query', () => {
+              it('will be treated as ordinary characters', async () => {
+                variables = { query: '„teeei“' }
+                await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+                  data: {
+                    findResources: [
+                      {
+                        __typename: 'Post',
+                        id: 'g-post',
+                        title: 'Zusammengesetzte Wörter',
+                        content: `Ein Bindestrich kann zwischen zwei Substantiven auch dann gesetzt werden, wenn drei gleichlautende Buchstaben aufeinandertreffen. Das ist etwa bei einem „Teeei“ der Fall, das so korrekt geschrieben ist. Möglich ist hier auch die Schreibweise mit Bindestrich: Tee-Ei.`,
+                      },
+                    ],
+                  },
+                })
+              })
+            })
+          })
+
+          describe('a post that contains a simple mathematical exprssion and linebreaks', () => {
+            describe('query a part of the mathematical expression', () => {
+              it('finds that post', async () => {
+                variables = { query: '(a - b)²' }
+                await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+                  data: {
+                    findResources: [
+                      {
+                        __typename: 'Post',
+                        id: 'c-post',
+                        title: 'Die binomischen Formeln',
+                        content: `1. binomische Formel: (a + b)² = a² + 2ab + b²<br>
+2. binomische Formel: (a - b)² = a² - 2ab + b²<br>
+3. binomische Formel: (a + b)(a - b) = a² - b²`,
+                      },
+                    ],
+                  },
+                })
+              })
+            })
+
+            describe('query the same part of the mathematical expression without spaces', () => {
+              it('finds that post', async () => {
+                variables = { query: '(a-b)²' }
+                await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+                  data: {
+                    findResources: [
+                      {
+                        __typename: 'Post',
+                        id: 'c-post',
+                        title: 'Die binomischen Formeln',
+                        content: `1. binomische Formel: (a + b)² = a² + 2ab + b²<br>
+2. binomische Formel: (a - b)² = a² - 2ab + b²<br>
+3. binomische Formel: (a + b)(a - b) = a² - b²`,
+                      },
+                    ],
+                  },
+                })
+              })
+            })
+
+            describe('query the mathematical expression over linebreak', () => {
+              it('finds that post', async () => {
+                variables = { query: '+ b² 2.' }
+                await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
+                  data: {
+                    findResources: [
+                      {
+                        __typename: 'Post',
+                        id: 'c-post',
+                        title: 'Die binomischen Formeln',
+                        content: `1. binomische Formel: (a + b)² = a² + 2ab + b²<br>
+2. binomische Formel: (a - b)² = a² - 2ab + b²<br>
+3. binomische Formel: (a + b)(a - b) = a² - b²`,
+                      },
+                    ],
+                  },
+                })
+              })
+            })
+          })
+
+          describe('a post that contains a poem', () => {

I don't understand where the poem part makes a search different 🤔

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mogge Authored by Mogge
Mar 17, 2020


It is just for the beauty of the poem. Be happy, that I did not include the second and third verse.

}

const matchWholeText = (str, boost = 8) => {
return `"${str}"^${boost}`
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mattwr18 Authored by mattwr18
Mar 17, 2020


Outdated (history rewrite) - original diff


@@ -0,0 +1,53 @@
+export function queryString(str) {
+  const normalizedString = normalizeWhitespace(str)
+  const escapedString = escapeSpecialCharacters(normalizedString)
+  return `
+${matchWholeText(escapedString)}
+${matchEachWordExactly(escapedString)}
+${matchSomeWordsExactly(escapedString)}
+${matchBeginningOfWords(escapedString)}
+`
+}
+
+const matchWholeText = (str, boost = 8) => {
+  return `"${str}"^${boost}`

thank you for giving the docs so that your reviewers can understand how the boost works!
I didn't really understand how you came to the defaults. Maybe you could explain?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mogge Authored by Mogge
Mar 17, 2020


I thought: 1, 2, 4, 8
Next would be 16
Matching the whole query exactly -> 8
Matching all words exactly -> 4
Matching at least one word exactly -> 2
Match the beginning of some words -> 1

})

describe('whitespace', () => {
it('normalizes correctly', () => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mattwr18 Authored by mattwr18
Mar 17, 2020


Outdated (history rewrite) - original diff


@@ -0,0 +1,43 @@
+import { queryString, escapeSpecialCharacters, normalizeWhitespace } from './queryString'
+
+describe('queryString', () => {
+  describe('special characters', () => {
+    it('does escaping correctly', () => {
+      expect(escapeSpecialCharacters('+ - && || ! ( ) { } [ ] ^ " ~ * ? : \\ / ')).toEqual(
+        '\\+ \\- \\&\\& \\|\\| \\! \\( \\) \\{ \\} \\[ \\] \\^ \\" \\~ \\* \\? \\: \\\\ \\/ ',
+      )
+    })
+  })
+
+  describe('whitespace', () => {
+    it('is normalized correctly', () => {
Suggested change
it('normalizes correctly', () => {
it('normalizes correctly', () => {

it('boosts score by factor 2', () => {
expect(queryString('a couple of words')).toContain('"a"^2 "couple"^2 "of"^2 "words"^2')
})
})
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mattwr18 Authored by mattwr18
Mar 17, 2020


Outdated (history rewrite) - original diff


@@ -0,0 +1,43 @@
+import { queryString, escapeSpecialCharacters, normalizeWhitespace } from './queryString'
+
+describe('queryString', () => {
+  describe('special characters', () => {
+    it('does escaping correctly', () => {
+      expect(escapeSpecialCharacters('+ - && || ! ( ) { } [ ] ^ " ~ * ? : \\ / ')).toEqual(
+        '\\+ \\- \\&\\& \\|\\| \\! \\( \\) \\{ \\} \\[ \\] \\^ \\" \\~ \\* \\? \\: \\\\ \\/ ',
+      )
+    })
+  })
+
+  describe('whitespace', () => {
+    it('is normalized correctly', () => {
+      expect(normalizeWhitespace(' a \t \n b \n   ')).toEqual('a b')
+    })
+  })
+
+  describe('exact match', () => {
+    it('boosts score by factor 8', () => {
+      expect(queryString('a couple of words')).toContain('"a couple of words"^8')
+    })
+  })
+
+  describe('match all words exactly', () => {
+    it('boosts score by factor 4', () => {
+      expect(queryString('a couple of words')).toContain(
+        '("a" AND "couple" AND "of" AND "words")^4',
+      )
+    })
+  })
+
+  describe('match at least one word exactly', () => {
+    it('boosts score by factor 2', () => {
+      expect(queryString('a couple of words')).toContain('"a"^2 "couple"^2 "of"^2 "words"^2')
+    })
+  })

I guess these tests give a hint of how the boosting works... I would infer that 8 is the maximum and you can evenly distribute that amongst words?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mogge Authored by Mogge
Mar 17, 2020


As far as I know, there is no maximum.

@Tirokk
Copy link
Member Author

Tirokk commented Oct 7, 2020

Mogge Authored by Mogge
Mar 17, 2020


Thank you for the review, @mattwr18

@Tirokk
Copy link
Member Author

Tirokk commented Oct 7, 2020

mattwr18 Authored by mattwr18
Mar 18, 2020


Thanks @Mogge !!!

@Mogge Mogge closed this Oct 8, 2020
@ulfgebhardt ulfgebhardt deleted the pr3199head branch January 7, 2021 04:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants