diff --git a/src/renderer/controllers/torrent-list-controller.js b/src/renderer/controllers/torrent-list-controller.js
index 9aeb06cb..8bfc2b48 100644
--- a/src/renderer/controllers/torrent-list-controller.js
+++ b/src/renderer/controllers/torrent-list-controller.js
@@ -215,11 +215,41 @@ module.exports = class TorrentListController {
menu.append(new electron.remote.MenuItem({
label: 'Save Torrent File As...',
- click: () => saveTorrentFileAs(torrentSummary)
+ click: () => dispatch('saveTorrentFileAs', torrentSummary.torrentKey)
}))
menu.popup(electron.remote.getCurrentWindow())
}
+
+ // Takes a torrentSummary or torrentKey
+ // Shows a Save File dialog, then saves the .torrent file wherever the user requests
+ saveTorrentFileAs (torrentKey) {
+ const torrentSummary = TorrentSummary.getByKey(this.state, torrentKey)
+ if (!torrentSummary) throw new Error('Missing torrentKey: ' + torrentKey)
+ const downloadPath = this.state.saved.prefs.downloadPath
+ const newFileName = path.parse(torrentSummary.name).name + '.torrent'
+ const win = electron.remote.getCurrentWindow()
+ const opts = {
+ title: 'Save Torrent File',
+ defaultPath: path.join(downloadPath, newFileName),
+ filters: [
+ { name: 'Torrent Files', extensions: ['torrent'] },
+ { name: 'All Files', extensions: ['*'] }
+ ]
+ }
+
+ electron.remote.dialog.showSaveDialog(win, opts, function (savePath) {
+ console.log('Saving torrent ' + torrentKey + ' to ' + savePath)
+ if (!savePath) return // They clicked Cancel
+ const torrentPath = TorrentSummary.getTorrentPath(torrentSummary)
+ fs.readFile(torrentPath, function (err, torrentFile) {
+ if (err) return dispatch('error', err)
+ fs.writeFile(savePath, torrentFile, function (err) {
+ if (err) return dispatch('error', err)
+ })
+ })
+ })
+ }
}
// Recursively finds {name, path, size} for all files in a folder
@@ -280,27 +310,3 @@ function moveItemToTrash (torrentSummary) {
function showItemInFolder (torrentSummary) {
ipcRenderer.send('showItemInFolder', TorrentSummary.getFileOrFolder(torrentSummary))
}
-
-function saveTorrentFileAs (torrentSummary) {
- const downloadPath = this.state.saved.prefs.downloadPath
- const newFileName = path.parse(torrentSummary.name).name + '.torrent'
- const opts = {
- title: 'Save Torrent File',
- defaultPath: path.join(downloadPath, newFileName),
- filters: [
- { name: 'Torrent Files', extensions: ['torrent'] },
- { name: 'All Files', extensions: ['*'] }
- ]
- }
- const win = electron.remote.getCurrentWindow()
- electron.remote.dialog.showSaveDialog(win, opts, function (savePath) {
- if (!savePath) return // They clicked Cancel
- const torrentPath = TorrentSummary.getTorrentPath(torrentSummary)
- fs.readFile(torrentPath, function (err, torrentFile) {
- if (err) return dispatch('error', err)
- fs.writeFile(savePath, torrentFile, function (err) {
- if (err) return dispatch('error', err)
- })
- })
- })
-}
diff --git a/src/renderer/main.js b/src/renderer/main.js
index aa99deec..3c2cbdf0 100644
--- a/src/renderer/main.js
+++ b/src/renderer/main.js
@@ -194,6 +194,8 @@ const dispatchHandlers = {
controllers.torrentList.openTorrentContextMenu(infoHash),
'startTorrentingSummary': (torrentKey) =>
controllers.torrentList.startTorrentingSummary(torrentKey),
+ 'saveTorrentFileAs': (torrentKey) =>
+ controllers.torrentList.saveTorrentFileAs(torrentKey),
// Playback
'playFile': (infoHash, index) => controllers.playback.playFile(infoHash, index),
diff --git a/src/renderer/pages/create-torrent-page.js b/src/renderer/pages/create-torrent-page.js
index 687ddfb9..357295bf 100644
--- a/src/renderer/pages/create-torrent-page.js
+++ b/src/renderer/pages/create-torrent-page.js
@@ -99,14 +99,14 @@ class CreateTorrentPage extends React.Component {
diff --git a/test/config.js b/test/config.js
new file mode 100644
index 00000000..e1a5dc1c
--- /dev/null
+++ b/test/config.js
@@ -0,0 +1,14 @@
+const path = require('path')
+
+const TEST_DIR = path.join(__dirname, 'tempTestData')
+const TEST_DIR_DOWNLOAD = path.join(TEST_DIR, 'Downloads')
+const TEST_DIR_DESKTOP = path.join(TEST_DIR, 'Desktop')
+
+module.exports = {
+ TORRENT_FILES: [path.join(__dirname, 'resources', '1.torrent')],
+ SEED_FILES: [path.join(TEST_DIR_DESKTOP, 'tmp.jpg')],
+ SAVED_TORRENT_FILE: path.join(TEST_DIR_DESKTOP, 'saved.torrent'),
+ TEST_DIR,
+ TEST_DIR_DOWNLOAD,
+ TEST_DIR_DESKTOP
+}
diff --git a/test/index.js b/test/index.js
index 7373b84f..34362b5d 100644
--- a/test/index.js
+++ b/test/index.js
@@ -1,17 +1,11 @@
const test = require('tape')
-const fs = require('fs-extra')
const setup = require('./setup')
-console.log('Creating download dir: ' + setup.TEST_DOWNLOAD_DIR)
-fs.mkdirpSync(setup.TEST_DOWNLOAD_DIR)
-
-test.onFinish(function () {
- console.log('Removing test dir: ' + setup.TEST_DATA_DIR)
- fs.removeSync(setup.TEST_DATA_DIR) // includes download dir
-})
+test.onFinish(setup.deleteTestDataDir)
test('app runs', function (t) {
t.timeoutAfter(10e3)
+ setup.resetTestDataDir()
const app = setup.createApp()
setup.waitForLoad(app, t)
.then(() => setup.wait())
@@ -20,12 +14,11 @@ test('app runs', function (t) {
(err) => setup.endTest(app, t, err || 'error'))
})
-// require('./test-torrent-list')
+require('./test-torrent-list')
require('./test-add-torrent')
// TODO:
-// require('./test-create-torrent')
-// require('./test-prefs')
// require('./test-video')
// require('./test-audio')
// require('./test-cast')
+// require('./test-prefs')
diff --git a/test/mocks.js b/test/mocks.js
index 730d1dbc..6a27b937 100644
--- a/test/mocks.js
+++ b/test/mocks.js
@@ -1,9 +1,15 @@
-const path = require('path')
const electron = require('electron')
+const config = require('./config')
-const MOCK_OPEN_TORRENTS = [path.join(__dirname, 'resources', '1.torrent')]
-
-console.log('Mocking electron native integrations...')
+console.log('Mocking electron.dialog.showOpenDialog...')
electron.dialog.showOpenDialog = function (win, opts, cb) {
- cb(MOCK_OPEN_TORRENTS)
+ const ret = /select.*torrent file/i.test(opts.title)
+ ? config.TORRENT_FILES
+ : config.SEED_FILES
+ cb(ret)
+}
+
+console.log('Mocking electron.remote.dialog.showSaveDialog...')
+electron.dialog.showSaveDialog = function (win, opts, cb) {
+ cb(config.SAVED_TORRENT_FILE)
}
diff --git a/test/resources/expected-single-file.torrent b/test/resources/expected-single-file.torrent
new file mode 100644
index 00000000..920c02dc
Binary files /dev/null and b/test/resources/expected-single-file.torrent differ
diff --git a/test/screenshots/darwin/add-torrent-0-percent.png b/test/screenshots/darwin/add-torrent-0-percent.png
new file mode 100644
index 00000000..bcd3d551
Binary files /dev/null and b/test/screenshots/darwin/add-torrent-0-percent.png differ
diff --git a/test/screenshots/darwin/add-torrent-100-percent.png b/test/screenshots/darwin/add-torrent-100-percent.png
new file mode 100644
index 00000000..85356bd9
Binary files /dev/null and b/test/screenshots/darwin/add-torrent-100-percent.png differ
diff --git a/test/screenshots/darwin/add-torrent-existing-1.png b/test/screenshots/darwin/add-torrent-existing-1.png
deleted file mode 100644
index 93a24ac8..00000000
Binary files a/test/screenshots/darwin/add-torrent-existing-1.png and /dev/null differ
diff --git a/test/screenshots/darwin/add-torrent-existing-2.png b/test/screenshots/darwin/add-torrent-existing-2.png
deleted file mode 100644
index 4b627997..00000000
Binary files a/test/screenshots/darwin/add-torrent-existing-2.png and /dev/null differ
diff --git a/test/screenshots/darwin/create-torrent-100-percent.png b/test/screenshots/darwin/create-torrent-100-percent.png
new file mode 100644
index 00000000..26087fc8
Binary files /dev/null and b/test/screenshots/darwin/create-torrent-100-percent.png differ
diff --git a/test/screenshots/darwin/create-torrent-advanced.png b/test/screenshots/darwin/create-torrent-advanced.png
new file mode 100644
index 00000000..e02233ea
Binary files /dev/null and b/test/screenshots/darwin/create-torrent-advanced.png differ
diff --git a/test/screenshots/darwin/create-torrent-simple.png b/test/screenshots/darwin/create-torrent-simple.png
new file mode 100644
index 00000000..5c10b836
Binary files /dev/null and b/test/screenshots/darwin/create-torrent-simple.png differ
diff --git a/test/setup.js b/test/setup.js
index 4e6d179c..5f36d6a1 100644
--- a/test/setup.js
+++ b/test/setup.js
@@ -1,20 +1,20 @@
const path = require('path')
const Application = require('spectron').Application
const fs = require('fs-extra')
-
-const TEST_DATA_DIR = path.join(__dirname, 'tempTestData')
-const TEST_DOWNLOAD_DIR = path.join(TEST_DATA_DIR, 'Downloads')
+const parseTorrent = require('parse-torrent')
+const config = require('./config')
module.exports = {
- TEST_DATA_DIR,
- TEST_DOWNLOAD_DIR,
createApp,
endTest,
screenshotCreateOrCompare,
compareDownloadFolder,
+ compareFiles,
+ compareTorrentFiles,
waitForLoad,
wait,
- wipeTestDataDir
+ resetTestDataDir,
+ deleteTestDataDir
}
// Runs WebTorrent Desktop.
@@ -92,16 +92,22 @@ function screenshotCreateOrCompare (app, t, name) {
}
// Resets the test directory, containing config.json, torrents, downloads, etc
-function wipeTestDataDir () {
- fs.removeSync(TEST_DATA_DIR)
- fs.mkdirpSync(TEST_DOWNLOAD_DIR) // Downloads/ is inside of TEST_DATA_DIR
+function resetTestDataDir () {
+ fs.removeSync(config.TEST_DIR)
+ // Create TEST_DIR as well as /Downloads and /Desktop
+ fs.mkdirpSync(config.TEST_DIR_DOWNLOAD)
+ fs.mkdirpSync(config.TEST_DIR_DESKTOP)
+}
+
+function deleteTestDataDir () {
+ fs.removeSync(config.TEST_DIR)
}
// Checks a given folder under Downloads.
// Makes sure that the filenames match exactly.
// If `filenames` is null, asserts that the folder doesn't exist.
function compareDownloadFolder (t, dirname, filenames) {
- const dirpath = path.join(TEST_DOWNLOAD_DIR, dirname)
+ const dirpath = path.join(config.TEST_DIR_DOWNLOAD, dirname)
try {
const actualFilenames = fs.readdirSync(dirpath)
const expectedSorted = filenames.slice().sort()
@@ -116,3 +122,26 @@ function compareDownloadFolder (t, dirname, filenames) {
}
}
}
+
+// Makes sure two files have identical contents
+function compareFiles (t, pathActual, pathExpected) {
+ const bufActual = fs.readFileSync(pathActual)
+ const bufExpected = fs.readFileSync(pathExpected)
+ const match = Buffer.compare(bufActual, bufExpected) === 0
+ t.ok(match, 'correct contents: ' + pathActual)
+}
+
+// Makes sure two torrents have the same infohash and flags
+function compareTorrentFiles (t, pathActual, pathExpected) {
+ const bufActual = fs.readFileSync(pathActual)
+ const bufExpected = fs.readFileSync(pathExpected)
+ const fieldsActual = extractImportantFields(parseTorrent(bufActual))
+ const fieldsExpected = extractImportantFields(parseTorrent(bufExpected))
+ t.deepEqual(fieldsActual, fieldsExpected, 'torrent contents: ' + pathActual)
+}
+
+function extractImportantFields (parsedTorrent) {
+ const { infoHash, name, announce, urlList, comment } = parsedTorrent
+ const priv = parsedTorrent.private
+ return { infoHash, name, announce, urlList, comment, 'private': priv }
+}
diff --git a/test/test-add-torrent.js b/test/test-add-torrent.js
index 07782ba8..f234cc24 100644
--- a/test/test-add-torrent.js
+++ b/test/test-add-torrent.js
@@ -2,34 +2,68 @@ const test = require('tape')
const fs = require('fs-extra')
const path = require('path')
const setup = require('./setup')
+const config = require('./config')
test('add-torrent', function (t) {
- setup.wipeTestDataDir()
+ setup.resetTestDataDir()
- t.timeoutAfter(100e3)
+ t.timeoutAfter(30e3)
const app = setup.createApp()
setup.waitForLoad(app, t)
.then(() => app.client.waitUntilTextExists('.torrent-list', 'Big Buck Bunny'))
// Add an existing torrent. The corresponding file is not present. Should be at 0%
- .then(() => app.client.click('.icon.add'))
+ .then(() => app.electron.ipcRenderer.send('openTorrentFile'))
// The call to dialog.openFiles() is mocked. See mocks.js
.then(() => app.client.waitUntilTextExists('m3.jpg'))
- .then(() => setup.screenshotCreateOrCompare(app, t, 'add-torrent-existing-1'))
+ .then(() => setup.screenshotCreateOrCompare(app, t, 'add-torrent-0-percent'))
// Delete the torrent.
.then(() => app.client.moveToObject('.torrent'))
.then(() => setup.wait())
.then(() => app.client.click('.icon.delete'))
.then(() => app.client.waitUntilTextExists('REMOVE'))
.then(() => app.client.click('.control.ok'))
- .then(() => setup.wait())
// Add the same existing torrent, this time with the file present. Should be at 100%
.then(() => fs.copySync(
path.join(__dirname, 'resources', 'm3.jpg'),
- path.join(setup.TEST_DOWNLOAD_DIR, 'm3.jpg')))
- .then(() => app.client.click('.icon.add'))
+ path.join(config.TEST_DIR_DOWNLOAD, 'm3.jpg')))
+ .then(() => app.electron.ipcRenderer.send('openTorrentFile'))
.then(() => app.client.waitUntilTextExists('m3.jpg'))
.then(() => setup.wait())
- .then(() => setup.screenshotCreateOrCompare(app, t, 'add-torrent-existing-2'))
+ .then(() => setup.screenshotCreateOrCompare(app, t, 'add-torrent-100-percent'))
+ .then(() => setup.endTest(app, t),
+ (err) => setup.endTest(app, t, err || 'error'))
+})
+
+test('create-torrent', function (t) {
+ setup.resetTestDataDir()
+
+ // Set up the files to seed
+ fs.copySync(path.join(__dirname, 'resources', 'm3.jpg'), config.SEED_FILES[0])
+
+ t.timeoutAfter(30e3)
+ const app = setup.createApp()
+ setup.waitForLoad(app, t)
+ .then(() => app.client.waitUntilTextExists('.torrent-list', 'Big Buck Bunny'))
+ // Click the + button, open a non-torrent file to seed
+ .then(() => app.client.click('.icon.add'))
+ .then(() => app.client.waitUntilTextExists('Create'))
+ .then(() => setup.screenshotCreateOrCompare(app, t, 'create-torrent-simple'))
+ // Click to show advanced settings
+ .then(() => app.client.click('.show-more .control'))
+ .then(() => app.client.waitUntilTextExists('Comment'))
+ .then(() => setup.screenshotCreateOrCompare(app, t, 'create-torrent-advanced'))
+ // Click OK to create the torrent
+ .then(() => app.client.click('.control.create-torrent'))
+ .then(() => app.client.waitUntilTextExists('tmp.jpg'))
+ .then(() => setup.screenshotCreateOrCompare(app, t, 'create-torrent-100-percent'))
+ // Click "Save Torrent File As..." on the new torrent
+ .then(() => app.webContents.executeJavaScript(
+ 'dispatch("saveTorrentFileAs", 6)'))
+ .then(() => setup.wait())
+ // Mock saves to /Desktop/saved.torrent
+ .then(() => setup.compareTorrentFiles(t,
+ config.SAVED_TORRENT_FILE,
+ path.join(__dirname, 'resources', 'expected-single-file.torrent')))
.then(() => setup.endTest(app, t),
(err) => setup.endTest(app, t, err || 'error'))
})
diff --git a/test/test-torrent-list.js b/test/test-torrent-list.js
index 981cdc1e..e68e5e98 100644
--- a/test/test-torrent-list.js
+++ b/test/test-torrent-list.js
@@ -1,10 +1,11 @@
const test = require('tape')
const fs = require('fs-extra')
const setup = require('./setup')
+const config = require('./config')
test('torrent-list: show download path missing', function (t) {
- setup.wipeTestDataDir()
- fs.removeSync(setup.TEST_DOWNLOAD_DIR)
+ setup.resetTestDataDir()
+ fs.removeSync(config.TEST_DIR_DOWNLOAD)
t.timeoutAfter(10e3)
const app = setup.createApp()
@@ -24,7 +25,7 @@ test('torrent-list: show download path missing', function (t) {
})
test('torrent-list: start, stop, and delete torrents', function (t) {
- setup.wipeTestDataDir()
+ setup.resetTestDataDir()
const app = setup.createApp()
setup.waitForLoad(app, t, {offline: true})
@@ -35,7 +36,7 @@ test('torrent-list: start, stop, and delete torrents', function (t) {
.then(() => setup.screenshotCreateOrCompare(app, t, 'torrent-list-hover'))
// Click download on the first torrent, start downloading
.then(() => app.client.click('.icon.download'))
- .then(() => app.client.waitUntilTextExists('.torrent-list', '276 MB'))
+ .then(() => app.client.waitUntilTextExists('.torrent-list', 'peer'))
.then(() => setup.screenshotCreateOrCompare(app, t, 'torrent-list-start-download'))
// Click download on the first torrent again, stop downloading
.then(() => app.client.click('.icon.download'))
@@ -62,7 +63,7 @@ test('torrent-list: start, stop, and delete torrents', function (t) {
})
test('torrent-list: expand torrent, unselect file', function (t) {
- setup.wipeTestDataDir()
+ setup.resetTestDataDir()
const app = setup.createApp()
setup.waitForLoad(app, t, {offline: true})