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

[Work in Progress] Testing Suite #107

Closed
wants to merge 16 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .jest-config.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
{
"browser": true,
"globals": {
"browser": {}
},
"testMatch": [
"<rootDir>/src/**/*.test.(js|jsx)"
"<rootDir>/src/**/*.test.(js|jsx)",
"<rootDir>/test/**/*.app-test.(js|jsx)"
],
"rootDir": ".",
"transform": {
Expand Down
5 changes: 4 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ script:
- npm run test
- npm run lint
- npm run build
cache: yarn
notifications:
email: false
branches:
only:
- gsoc-ci
- /^test-.*$/
1 change: 1 addition & 0 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# WebMemex browser extension
![Build Image](https://travis-ci.org/reficul31/webmemex-extension.svg?branch=gsoc-ci)

A browser extension that lets you grow your personal web of knowledge.

Expand Down
41 changes: 41 additions & 0 deletions __mocks__/src/pouchdb.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import fromPairs from 'lodash/fp/fromPairs'
import PouchDB from 'pouchdb-core'

import PouchDBMemory from 'pouchdb-adapter-memory'
import PouchDBFind from 'pouchdb-find'
import mapreduce from 'pouchdb-mapreduce'
import replication from 'pouchdb-replication'

PouchDB
.plugin(PouchDBMemory)
.plugin(PouchDBFind)
.plugin(mapreduce)
.plugin(replication)

const pouchdbOptions = {
name: 'testdb',
auto_compaction: true,
adapter: 'memory',
}

const db = PouchDB(pouchdbOptions)
export default db

export const keyRangeForPrefix = prefix => ({
startkey: `${prefix}`,
endkey: `${prefix}\uffff`,
})

// Present db.find results in the same structure as other PouchDB results.
export const normaliseFindResult = result => ({
rows: result.docs.map(doc => ({
doc,
id: doc._id,
key: doc._id,
value: {rev: doc._rev},
})),
})

// Get rows of a query result indexed by doc id, as an {id: row} object.
export const resultRowsById = result =>
fromPairs(result.rows.map(row => [row.id, row]))
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"react-waypoint": "^7.0.4",
"redux": "^3.7.0",
"redux-act": "^1.3.0",
"redux-mock-store": "^1.2.3",
"redux-observable": "^0.14.1",
"redux-query-sync": "^0.1.5",
"redux-thunk": "^2.2.0",
Expand Down Expand Up @@ -91,13 +92,16 @@
"pify": "^3.0.0",
"postcss-cssnext": "^2.11.0",
"pouchdb-adapter-memory": "^6.2.0",
"pouchdb-node": "^6.2.0",
"pouchdb-core": "^6.3.4",
"pouchdb-mapreduce": "^6.3.4",
"pouchdb-replication": "^6.3.4",
"react-addons-test-utils": "^15.6.0",
"react-test-renderer": "^15.6.1",
"redux-devtools": "^3.4.0",
"redux-devtools-dock-monitor": "^1.1.2",
"redux-devtools-log-monitor": "^1.3.0",
"stream-to-promise": "^2.2.0",
"redux-mock-store": "^1.2.3",
"stylelint": "^7.11.1",
"stylelint-config-standard": "^16.0.0",
"uglifyify": "^4.0.1",
Expand Down
50 changes: 50 additions & 0 deletions setupJest.js
Original file line number Diff line number Diff line change
@@ -1 +1,51 @@
import iface from 'jsdom/lib/jsdom/living/generated/Element'

Element.prototype.insertAdjacentElement = function insertAdjacentElement(position, node) {
position = position.toLowerCase();

let context;
switch (position) {
case "beforebegin":
case "afterend": {
context = this.parentNode;
if (context === null || context.nodeType === NODE_TYPE.DOCUMENT_NODE) {
throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, "Cannot insert HTML adjacent to " +
"parent-less nodes or children of document nodes.");
}
break;
}
case "afterbegin":
case "beforeend": {
context = this;
break;
}
default: {
throw new DOMException(DOMException.SYNTAX_ERR, "Must provide one of \"beforebegin\", \"afterend\", " +"\"afterbegin\", or \"beforeend\".");
}
}

// TODO: use context for parsing instead of a <template>.
const fragment = this.ownerDocument.createElement("template");
fragment.innerHTML = node.outerHTML;

switch (position) {
case "beforebegin": {
this.parentNode.insertBefore(fragment.content, this);
break;
}
case "afterbegin": {
this.insertBefore(fragment.content, this.firstChild);
break;
}
case "beforeend": {
this.appendChild(fragment.content);
break;
}
case "afterend": {
this.parentNode.insertBefore(fragment.content, this.nextSibling);
break;
}
}
}

global.fetch = require('jest-fetch-mock')
124 changes: 124 additions & 0 deletions src/activity-logger/background/log-page-visit.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/* eslint-env jest */
/* eslint import/namespace: "off" */

import { maybeLogPageVisit, logPageVisit, logActivePageVisit } from 'src/activity-logger/background/log-page-visit'
import * as activityLogger from 'src/activity-logger'
import * as storePage from 'src/page-storage/store-page'
import * as tabEvents from 'src/util/tab-events'
import * as delay from 'src/util/delay'
import db from 'src/pouchdb'

jest.mock('src/util/webextensionRPC')

afterAll(async () => {
await db.destroy()
})

describe('maybeLogPageVisit', () => {
beforeAll(() => {
tabEvents.whenPageLoadComplete = jest.fn()
tabEvents.whenTabActive = jest.fn()
delay.default = jest.fn()
storePage.reidentifyOrStorePage = jest.fn().mockReturnValue({
page: {},
finalPagePromise: {},
})
})

test('should return if shouldBeLogged is false', async () => {
activityLogger.shouldBeLogged = jest.fn().mockReturnValueOnce(false)
tabEvents.whenPageLoadComplete = jest.fn()
await maybeLogPageVisit({tabId: 1, url: 'example.com'})
expect(tabEvents.whenPageLoadComplete).toHaveBeenCalledTimes(0)
})

test('should return if logging is disabled', async () => {
activityLogger.shouldBeLogged = jest.fn().mockReturnValue(true)
tabEvents.whenPageLoadComplete = jest.fn()
browser.storage = {
local: {
get: jest.fn().mockReturnValueOnce({
loggingEnabled: false,
}),
},
}
await maybeLogPageVisit({tabId: 1, url: 'example.com'})
expect(tabEvents.whenPageLoadComplete).toHaveBeenCalledTimes(0)
})

test('should call the delay and tab functions and the tabEvents when logging is enabled', async () => {
expect.assertions(3)
activityLogger.shouldBeLogged = jest.fn().mockReturnValue(true)
browser.storage = {
local: {
get: jest.fn().mockReturnValueOnce({
loggingEnabled: true,
}),
},
}
await maybeLogPageVisit({tabId: 1, url: 'https://example.com'})
expect(delay.default).toHaveBeenCalled()
expect(tabEvents.whenPageLoadComplete).toHaveBeenCalled()
expect(tabEvents.whenTabActive).toHaveBeenCalled()
})
})

describe('logPageVisit', () => {
beforeAll(() => {
activityLogger.generateVisitDocId = jest.fn().mockReturnValue('visit/1234567890123/1234567890')
db.put = jest.fn()
storePage.reidentifyOrStorePage = jest.fn().mockReturnValue({
page: {
_id: 'page/1234567890123/1234567890',
},
finalPagePromise: {},
})
Date.now = jest.fn().mockReturnValue('1234567890123')
})

test('should call reidentifyOrStorePage function', async () => {
await logPageVisit({tabId: 1, url: 'https://example.com'})
expect(storePage.reidentifyOrStorePage).toHaveBeenCalledWith({tabId: 1, url: 'https://example.com'})
})

test('should call the database function with the visit object', async () => {
const visit = {
_id: 'visit/1234567890123/1234567890',
visitStart: '1234567890123',
url: 'https://example.com',
page: {_id: 'page/1234567890123/1234567890'},
}
await logPageVisit({tabId: 1, url: 'https://example.com'})
expect(db.put).toHaveBeenCalledWith(visit)
})
})

describe('logActivePageVisit', async () => {
beforeAll(() => {
browser.tabs = {
query: jest.fn().mockReturnValue([{
url: 'https://example.com/page',
id: 1,
}]),
}
})

test('should throw an error if isLoggable is false', async () => {
activityLogger.isLoggable = jest.fn().mockReturnValueOnce(false)
try {
await logActivePageVisit()
} catch (e) {
expect(e.toString()).toMatch('This page cannot be stored.')
}
})

test('should call logPageVisit if isLoggable is true', async () => {
storePage.reidentifyOrStorePage = jest.fn().mockReturnValue({
page: {},
finalPagePromise: {},
})
activityLogger.isLoggable = jest.fn().mockReturnValueOnce(true)
await logActivePageVisit()
expect(storePage.reidentifyOrStorePage).toHaveBeenCalled()
})
})
69 changes: 69 additions & 0 deletions src/activity-logger/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/* eslint-env jest */

import {isLoggable, generateVisitDocId, convertVisitDocId, getTimestamp, shouldBeLogged} from 'src/activity-logger'
import randomString from 'src/util/random-string'

describe('isLoggable', () => {
test('should accept links of type https://example.com', () => {
expect(isLoggable({url: 'https://example.com'})).toBe(true)
})

test('should reject links of type example.com', () => {
expect(isLoggable({url: 'example.com'})).toBe(false)
})

test('should accept links of type http://example.com', () => {
expect(isLoggable({url: 'http://example.com'})).toBe(true)
})

test('should reject links of new tab', () => {
expect(isLoggable({url: 'about:blank'})).toBe(false)
})

test('should reject links of data urls', () => {
expect(isLoggable({url: 'data:image/gif;base64,R0lGODlhyAAiALMDfD0QAADs='})).toBe(false)
})
})

describe('shouldBeLogged', () => {
test('should accept links of type https://example.com', () => {
expect(shouldBeLogged({url: 'https://example.com'})).toBe(true)
})

test('should reject links of type example.com', () => {
expect(shouldBeLogged({url: 'example.com'})).toBe(false)
})
})

describe('generateVisitDocId', () => {
test('should return visit docid with timestamp and nonce', () => {
const timestamp = Date.now()
const nonce = randomString()
let docid = `visit/${timestamp}/${nonce}`
expect(generateVisitDocId({timestamp, nonce})).toBe(docid)
})

test('should return visit docid without arguments', () => {
let expected = expect.stringMatching('^visit/[0-9]{13}/[0-9]{10}$')
expect(generateVisitDocId()).toEqual(expected)
})
})

describe('getTimestamp', () => {
test('should return the timestamp for a given doc', () => {
const timestamp = Date.now()
let doc = {
_id: `visit/${timestamp}/1234567890`,
}
expect(getTimestamp(doc)).toEqual(timestamp)
})
})

describe('convertPageDocId', () => {
test('should return the visit doc containing the timestamp and nonce', () => {
const timestamp = Date.now()
const nonce = randomString()
let docId = `visit/${timestamp}/${nonce}`
expect(convertVisitDocId({timestamp, nonce})).toBe(docId)
})
})
Loading