Commit 80c90c52e4088319b7d48db43edeb53d3bba8ffe
Merge pull request #21 from ssbc/build-publish
Rename and pass testsmix irving authored on 3/16/2018, 3:48:22 AM
GitHub committed on 3/16/2018, 3:48:22 AM
Parent: ea9a423663b274022b27c3a9574fc2dfefa5b165
Parent: 7b830c35a60fe8e303f9e2f3a156a6f3516a8cb1
Files changed
poll/async/get.js | ||
---|---|---|
@@ -3,9 +3,9 @@ | ||
3 | 3 | const { isPoll, isPosition, isChooseOnePoll, isChooseOnePosition } = require('ssb-poll-schema') |
4 | 4 | isPoll.chooseOne = isChooseOnePoll |
5 | 5 | isPosition.chooseOne = isChooseOnePosition |
6 | 6 | const { ERROR_POSITION_TYPE } = require('../../types') |
7 | -const getResults = require('../../position/sync/chooseOneResults') | |
7 | +const getResults = require('../../position/sync/buildResults') | |
8 | 8 | const getMsgContent = require('../../lib/getMsgContent') |
9 | 9 | |
10 | 10 | module.exports = function (server) { |
11 | 11 | return function get (key, cb) { |
poll/async/chooseOne.js | ||
---|---|---|
@@ -1,13 +1,0 @@ | ||
1 | -const ChooseOne = require('../sync/chooseOne') | |
2 | -const { isPoll } = require('ssb-poll-schema') | |
3 | - | |
4 | -module.exports = function (server) { | |
5 | - return function publishChooseOne (opts, cb) { | |
6 | - const poll = ChooseOne(opts) | |
7 | - console.log('poll', poll) | |
8 | - console.log('isChooseOnePoll', require('../../isPoll')) | |
9 | - if (!isPoll.chooseOne(poll)) return cb(isPoll.chooseOne.errors) | |
10 | - | |
11 | - server.publish(poll, cb) | |
12 | - } | |
13 | -} |
poll/async/publishChooseOne.js | ||
---|---|---|
@@ -1,0 +1,13 @@ | ||
1 | +const ChooseOne = require('../sync/buildChooseOne') | |
2 | +const { isPoll } = require('ssb-poll-schema') | |
3 | + | |
4 | +module.exports = function (server) { | |
5 | + return function publishChooseOne (opts, cb) { | |
6 | + const poll = ChooseOne(opts) | |
7 | + console.log('poll', poll) | |
8 | + console.log('isChooseOnePoll', require('../../isPoll')) | |
9 | + if (!isPoll.chooseOne(poll)) return cb(isPoll.chooseOne.errors) | |
10 | + | |
11 | + server.publish(poll, cb) | |
12 | + } | |
13 | +} |
poll/sync/chooseOne.js | ||
---|---|---|
@@ -1,19 +1,0 @@ | ||
1 | -const Poll = require('./poll') | |
2 | -const { CHOOSE_ONE } = require('../../types') | |
3 | - | |
4 | -function ChooseOne ({ choices, title, closesAt, body, channel, recps, mentions }) { | |
5 | - return Poll({ | |
6 | - details: { | |
7 | - choices, | |
8 | - type: CHOOSE_ONE | |
9 | - }, | |
10 | - title, | |
11 | - closesAt, | |
12 | - body, | |
13 | - channel, | |
14 | - recps, | |
15 | - mentions | |
16 | - }) | |
17 | -} | |
18 | - | |
19 | -module.exports = ChooseOne |
poll/sync/buildChooseOne.js | ||
---|---|---|
@@ -1,0 +1,19 @@ | ||
1 | +const Poll = require('./buildPoll') | |
2 | +const { CHOOSE_ONE } = require('../../types') | |
3 | + | |
4 | +function ChooseOne ({ choices, title, closesAt, body, channel, recps, mentions }) { | |
5 | + return Poll({ | |
6 | + details: { | |
7 | + choices, | |
8 | + type: CHOOSE_ONE | |
9 | + }, | |
10 | + title, | |
11 | + closesAt, | |
12 | + body, | |
13 | + channel, | |
14 | + recps, | |
15 | + mentions | |
16 | + }) | |
17 | +} | |
18 | + | |
19 | +module.exports = ChooseOne |
poll/sync/poll.js | ||
---|---|---|
@@ -1,41 +1,0 @@ | ||
1 | -// var { link } = require('ssb-msg-schemas/util') | |
2 | -const {versionStrings: {V1_SCHEMA_VERSION_STRING}} = require('ssb-poll-schema') | |
3 | - | |
4 | -function Poll ({ details, title, closesAt, body, channel, recps, mentions }) { | |
5 | - var content = { type: 'poll', details, title, closesAt, version: V1_SCHEMA_VERSION_STRING } | |
6 | - | |
7 | - if (body) content.body = body | |
8 | - | |
9 | - // if (root) { | |
10 | - // root = link(root) | |
11 | - // if (!root) { throw new Error('root is not a valid link') } | |
12 | - // content.root = root | |
13 | - // } | |
14 | - // if (branch) { | |
15 | - // if (!root) { throw new Error('root is not a valid link') } | |
16 | - // branch = Array.isArray(branch) ? branch.map(link) : link(branch) | |
17 | - // if (!branch) { throw new Error('branch is not a valid link') } | |
18 | - // content.branch = branch | |
19 | - // } | |
20 | - // | |
21 | - // // NOTE mentions can be derived from text, | |
22 | - // // or we could leave it so you can manually notify people without having to at-mention spam the text | |
23 | - // if (mentions && (!Array.isArray(mentions) || mentions.length)) { | |
24 | - // mentions = links(mentions) | |
25 | - // if (!mentions || !mentions.length) { throw new Error('mentions are not valid links') } | |
26 | - // content.mentions = mentions | |
27 | - // } | |
28 | - // if (recps && (!Array.isArray(recps) || recps.length)) { | |
29 | - // recps = links(recps) | |
30 | - // if (!recps || !recps.length) { throw new Error('recps are not valid links') } | |
31 | - // content.recps = recps | |
32 | - // } | |
33 | - if (channel) { | |
34 | - if (typeof channel !== 'string') { throw new Error('channel must be a string') } | |
35 | - content.channel = channel | |
36 | - } | |
37 | - | |
38 | - return content | |
39 | -} | |
40 | - | |
41 | -module.exports = Poll |
poll/sync/buildPoll.js | ||
---|---|---|
@@ -1,0 +1,41 @@ | ||
1 | +// var { link } = require('ssb-msg-schemas/util') | |
2 | +const {versionStrings: {V1_SCHEMA_VERSION_STRING}} = require('ssb-poll-schema') | |
3 | + | |
4 | +function Poll ({ details, title, closesAt, body, channel, recps, mentions }) { | |
5 | + var content = { type: 'poll', details, title, closesAt, version: V1_SCHEMA_VERSION_STRING } | |
6 | + | |
7 | + if (body) content.body = body | |
8 | + | |
9 | + // if (root) { | |
10 | + // root = link(root) | |
11 | + // if (!root) { throw new Error('root is not a valid link') } | |
12 | + // content.root = root | |
13 | + // } | |
14 | + // if (branch) { | |
15 | + // if (!root) { throw new Error('root is not a valid link') } | |
16 | + // branch = Array.isArray(branch) ? branch.map(link) : link(branch) | |
17 | + // if (!branch) { throw new Error('branch is not a valid link') } | |
18 | + // content.branch = branch | |
19 | + // } | |
20 | + // | |
21 | + // // NOTE mentions can be derived from text, | |
22 | + // // or we could leave it so you can manually notify people without having to at-mention spam the text | |
23 | + // if (mentions && (!Array.isArray(mentions) || mentions.length)) { | |
24 | + // mentions = links(mentions) | |
25 | + // if (!mentions || !mentions.length) { throw new Error('mentions are not valid links') } | |
26 | + // content.mentions = mentions | |
27 | + // } | |
28 | + // if (recps && (!Array.isArray(recps) || recps.length)) { | |
29 | + // recps = links(recps) | |
30 | + // if (!recps || !recps.length) { throw new Error('recps are not valid links') } | |
31 | + // content.recps = recps | |
32 | + // } | |
33 | + if (channel) { | |
34 | + if (typeof channel !== 'string') { throw new Error('channel must be a string') } | |
35 | + content.channel = channel | |
36 | + } | |
37 | + | |
38 | + return content | |
39 | +} | |
40 | + | |
41 | +module.exports = Poll |
position/async/chooseOne.js | ||
---|---|---|
@@ -1,18 +1,0 @@ | ||
1 | -const createPosition = require('./position') | |
2 | -const { CHOOSE_ONE } = require('../../types') | |
3 | - | |
4 | -module.exports = function (server) { | |
5 | - const Position = createPosition(server) | |
6 | - return function ChooseOne ({ poll, choice, reason, channel, mentions }, cb) { | |
7 | - Position({ | |
8 | - poll, | |
9 | - details: { | |
10 | - type: CHOOSE_ONE, | |
11 | - choice | |
12 | - }, | |
13 | - reason, | |
14 | - channel, | |
15 | - mentions | |
16 | - }, cb) | |
17 | - } | |
18 | -} |
position/async/buildChooseOne.js | ||
---|---|---|
@@ -1,0 +1,18 @@ | ||
1 | +const createPosition = require('./buildPosition') | |
2 | +const { CHOOSE_ONE } = require('../../types') | |
3 | + | |
4 | +module.exports = function (server) { | |
5 | + const Position = createPosition(server) | |
6 | + return function ChooseOne ({ poll, choice, reason, channel, mentions }, cb) { | |
7 | + Position({ | |
8 | + poll, | |
9 | + details: { | |
10 | + type: CHOOSE_ONE, | |
11 | + choice | |
12 | + }, | |
13 | + reason, | |
14 | + channel, | |
15 | + mentions | |
16 | + }, cb) | |
17 | + } | |
18 | +} |
position/async/position.js | ||
---|---|---|
@@ -1,50 +1,0 @@ | ||
1 | -const sort = require('ssb-sort') | |
2 | - | |
3 | -const GetPoll = require('../../poll/async/get') | |
4 | -const {versionStrings: {V1_SCHEMA_VERSION_STRING}} = require('ssb-poll-schema') | |
5 | -// var { link } = require('ssb-msg-schemas/util') | |
6 | -// | |
7 | - | |
8 | -module.exports = function (server) { | |
9 | - const getPoll = GetPoll(server) | |
10 | - | |
11 | - return function Position ({ poll = {}, details, reason, channel, mentions }, cb) { | |
12 | - const content = { | |
13 | - type: 'position', | |
14 | - version: V1_SCHEMA_VERSION_STRING, | |
15 | - root: typeof poll === 'string' ? poll : poll.key, | |
16 | - details | |
17 | - } | |
18 | - | |
19 | - if (reason) content.reason = reason | |
20 | - | |
21 | - if (channel) { | |
22 | - if (typeof channel !== 'string') { throw new Error('channel must be a string') } | |
23 | - content.channel = channel | |
24 | - } | |
25 | - | |
26 | - if (content.root && server) { | |
27 | - getPoll(content.root, (err, {positions}) => { | |
28 | - content.branch = sort.heads(positions) | |
29 | - cb(err, content) | |
30 | - }) | |
31 | - } else { | |
32 | - cb(null, content) | |
33 | - } | |
34 | - | |
35 | - // // NOTE mentions can be derived from text, | |
36 | - // // or we could leave it so you can manually notify people without having to at-mention spam the text | |
37 | - // if (mentions && (!Array.isArray(mentions) || mentions.length)) { | |
38 | - // mentions = links(mentions) | |
39 | - // if (!mentions || !mentions.length) { throw new Error('mentions are not valid links') } | |
40 | - // content.mentions = mentions | |
41 | - // } | |
42 | - | |
43 | - // // NOTE recps should be derived from the poll I think | |
44 | - // if (recps && (!Array.isArray(recps) || recps.length)) { | |
45 | - // recps = links(recps) | |
46 | - // if (!recps || !recps.length) { throw new Error('recps are not valid links') } | |
47 | - // content.recps = recps | |
48 | - // } | |
49 | - } | |
50 | -} |
position/async/buildPosition.js | ||
---|---|---|
@@ -1,0 +1,50 @@ | ||
1 | +const sort = require('ssb-sort') | |
2 | + | |
3 | +const GetPoll = require('../../poll/async/get') | |
4 | +const {versionStrings: {V1_SCHEMA_VERSION_STRING}} = require('ssb-poll-schema') | |
5 | +// var { link } = require('ssb-msg-schemas/util') | |
6 | +// | |
7 | + | |
8 | +module.exports = function (server) { | |
9 | + const getPoll = GetPoll(server) | |
10 | + | |
11 | + return function Position ({ poll = {}, details, reason, channel, mentions }, cb) { | |
12 | + const content = { | |
13 | + type: 'position', | |
14 | + version: V1_SCHEMA_VERSION_STRING, | |
15 | + root: typeof poll === 'string' ? poll : poll.key, | |
16 | + details | |
17 | + } | |
18 | + | |
19 | + if (reason) content.reason = reason | |
20 | + | |
21 | + if (channel) { | |
22 | + if (typeof channel !== 'string') { throw new Error('channel must be a string') } | |
23 | + content.channel = channel | |
24 | + } | |
25 | + | |
26 | + if (content.root && server) { | |
27 | + getPoll(content.root, (err, {positions}) => { | |
28 | + content.branch = sort.heads(positions) | |
29 | + cb(err, content) | |
30 | + }) | |
31 | + } else { | |
32 | + cb(null, content) | |
33 | + } | |
34 | + | |
35 | + // // NOTE mentions can be derived from text, | |
36 | + // // or we could leave it so you can manually notify people without having to at-mention spam the text | |
37 | + // if (mentions && (!Array.isArray(mentions) || mentions.length)) { | |
38 | + // mentions = links(mentions) | |
39 | + // if (!mentions || !mentions.length) { throw new Error('mentions are not valid links') } | |
40 | + // content.mentions = mentions | |
41 | + // } | |
42 | + | |
43 | + // // NOTE recps should be derived from the poll I think | |
44 | + // if (recps && (!Array.isArray(recps) || recps.length)) { | |
45 | + // recps = links(recps) | |
46 | + // if (!recps || !recps.length) { throw new Error('recps are not valid links') } | |
47 | + // content.recps = recps | |
48 | + // } | |
49 | + } | |
50 | +} |
position/sync/chooseOneResults.js | ||
---|---|---|
@@ -1,66 +1,0 @@ | ||
1 | -const getMsgContent = require('../../lib/getMsgContent') | |
2 | -const ChooseOne = require('../../poll/sync/chooseOne') | |
3 | -const PositionChoiceError = require('../../errors/sync/positionChoiceError') | |
4 | -const PositionLateError = require('../../errors/sync/positionLateError') | |
5 | - | |
6 | -// Expects `poll` and `position` objects passed in to be of shape: | |
7 | -// { | |
8 | -// key, | |
9 | -// value: { | |
10 | -// content: {...}, | |
11 | -// timestamp: ... | |
12 | -// author: ... | |
13 | -// } | |
14 | -// } | |
15 | -// | |
16 | -// postions must be of the correct type ie: type checked by the caller. | |
17 | -module.exports = function chooseOneResults ({positions, poll}) { | |
18 | - var results = getMsgContent(poll) | |
19 | - .details | |
20 | - .choices | |
21 | - .map(choice => { | |
22 | - return { | |
23 | - choice, | |
24 | - voters: {} | |
25 | - } | |
26 | - }) | |
27 | - | |
28 | - return positions.reduce(function (acc, position) { | |
29 | - const { author, content } = position.value | |
30 | - const { choice } = content.details | |
31 | - | |
32 | - if (isInvalidChoice({position, poll})) { | |
33 | - acc.errors.push(PositionChoiceError({position})) | |
34 | - return acc | |
35 | - } | |
36 | - | |
37 | - if (isPositionLate({position, poll})) { | |
38 | - acc.errors.push(PositionLateError({position})) | |
39 | - return acc | |
40 | - } | |
41 | - | |
42 | - deleteExistingVotesByAuthor({results: acc.results, author}) | |
43 | - acc.results[choice].voters[author] = position | |
44 | - | |
45 | - return acc | |
46 | - }, {errors: [], results}) | |
47 | -} | |
48 | - | |
49 | -// !!! assumes these are already sorted by time. | |
50 | -// modifies results passed in | |
51 | -function deleteExistingVotesByAuthor ({author, results}) { | |
52 | - results.forEach(result => { | |
53 | - if (result.voters[author]) { | |
54 | - delete result.voters[author] | |
55 | - } | |
56 | - }) | |
57 | -} | |
58 | - | |
59 | -function isInvalidChoice ({position, poll}) { | |
60 | - const { choice } = position.value.content.details | |
61 | - return choice >= poll.value.content.details.choices.length | |
62 | -} | |
63 | - | |
64 | -function isPositionLate ({position, poll}) { | |
65 | - return position.value.timestamp > poll.value.content.closesAt | |
66 | -} |
position/sync/buildResults.js | ||
---|---|---|
@@ -1,0 +1,72 @@ | ||
1 | +const getMsgContent = require('../../lib/getMsgContent') | |
2 | +const PositionChoiceError = require('../../errors/sync/positionChoiceError') | |
3 | +const PositionLateError = require('../../errors/sync/positionLateError') | |
4 | +const { isChooseOnePoll } = require('ssb-poll-schema') | |
5 | + | |
6 | +// Expects `poll` and `position` objects passed in to be of shape: | |
7 | +// { | |
8 | +// key, | |
9 | +// value: { | |
10 | +// content: {...}, | |
11 | +// timestamp: ... | |
12 | +// author: ... | |
13 | +// } | |
14 | +// } | |
15 | +// | |
16 | +// postions must be of the correct type ie: type checked by the caller. | |
17 | +module.exports = function ({positions, poll}) { | |
18 | + if (isChooseOnePoll(poll)) { | |
19 | + return chooseOneResults({positions, poll}) | |
20 | + } | |
21 | +} | |
22 | + | |
23 | +function chooseOneResults ({positions, poll}) { | |
24 | + var results = getMsgContent(poll) | |
25 | + .details | |
26 | + .choices | |
27 | + .map(choice => { | |
28 | + return { | |
29 | + choice, | |
30 | + voters: {} | |
31 | + } | |
32 | + }) | |
33 | + | |
34 | + return positions.reduce(function (acc, position) { | |
35 | + const { author, content } = position.value | |
36 | + const { choice } = content.details | |
37 | + | |
38 | + if (isInvalidChoice({position, poll})) { | |
39 | + acc.errors.push(PositionChoiceError({position})) | |
40 | + return acc | |
41 | + } | |
42 | + | |
43 | + if (isPositionLate({position, poll})) { | |
44 | + acc.errors.push(PositionLateError({position})) | |
45 | + return acc | |
46 | + } | |
47 | + | |
48 | + deleteExistingVotesByAuthor({results: acc.results, author}) | |
49 | + acc.results[choice].voters[author] = position | |
50 | + | |
51 | + return acc | |
52 | + }, {errors: [], results}) | |
53 | +} | |
54 | + | |
55 | +// !!! assumes these are already sorted by time. | |
56 | +// modifies results passed in | |
57 | +function deleteExistingVotesByAuthor ({author, results}) { | |
58 | + results.forEach(result => { | |
59 | + if (result.voters[author]) { | |
60 | + delete result.voters[author] | |
61 | + } | |
62 | + }) | |
63 | +} | |
64 | + | |
65 | +function isInvalidChoice ({position, poll}) { | |
66 | + const { choice } = position.value.content.details | |
67 | + return choice >= poll.value.content.details.choices.length | |
68 | +} | |
69 | + | |
70 | +function isPositionLate ({position, poll}) { | |
71 | + return position.value.timestamp > poll.value.content.closesAt | |
72 | +} |
test/errors/sync/index.test.js | ||
---|---|---|
@@ -9,9 +9,9 @@ | ||
9 | 9 | const PositionTypeError = require('../../../errors/sync/positionTypeError') |
10 | 10 | const PositionLateError = require('../../../errors/sync/positionLateError') |
11 | 11 | const PositionChoiceError = require('../../../errors/sync/positionChoiceError') |
12 | 12 | |
13 | -const ChooseOne = require('../../../position/async/chooseOne')() | |
13 | +const ChooseOne = require('../../../position/async/buildChooseOne')() | |
14 | 14 | |
15 | 15 | test('positionTypeError', function (t) { |
16 | 16 | pull( |
17 | 17 | pullAsync(cb => { |
test/poll/async/get.test.js | ||
---|---|---|
@@ -1,17 +1,17 @@ | ||
1 | 1 | var test = require('tape') |
2 | 2 | var Server = require('scuttle-testbot') |
3 | 3 | var pull = require('pull-stream') |
4 | 4 | |
5 | -var ChooseOnePoll = require('../../../poll/sync/chooseOne') | |
5 | +var ChooseOnePoll = require('../../../poll/sync/buildChooseOne') | |
6 | 6 | var getPoll = require('../../../poll/async/get') |
7 | 7 | |
8 | 8 | Server |
9 | 9 | .use(require('ssb-backlinks')) |
10 | 10 | |
11 | 11 | var server = Server({name: 'testBotName'}) |
12 | 12 | |
13 | -var ChooseOne = require('../../../position/async/chooseOne')(server) | |
13 | +var ChooseOne = require('../../../position/async/buildChooseOne')(server) | |
14 | 14 | |
15 | 15 | var katie = server.createFeed() |
16 | 16 | var piet = server.createFeed() |
17 | 17 |
test/poll/sync/chooseOne.test.js | ||
---|---|---|
@@ -1,29 +1,0 @@ | ||
1 | -const test = require('tape') | |
2 | -const ChooseOne = require('../../../poll/sync/chooseOne') | |
3 | -const {isPoll, isChooseOnePoll} = require('ssb-poll-schema') | |
4 | - | |
5 | -test('Position - ChooseOne', function (t) { | |
6 | - var invalidPoll = ChooseOne({ | |
7 | - }) | |
8 | - t.false(isPoll(invalidPoll), 'invalid') | |
9 | - | |
10 | - var validPoll = ChooseOne({ | |
11 | - title: 'how many food', | |
12 | - choices: [1, 2, 'three'], | |
13 | - closesAt: new Date().toISOString() | |
14 | - }) | |
15 | - t.true(isPoll(validPoll), 'simple (passes isPoll)') | |
16 | - t.true(isChooseOnePoll(validPoll), 'simple (passes isChooseOnePoll)') | |
17 | - | |
18 | - var fullPollMsg = { | |
19 | - key: '%somekey', | |
20 | - value: { | |
21 | - content: validPoll | |
22 | - } | |
23 | - } | |
24 | - t.true(isPoll(fullPollMsg), 'simple (full msg)') | |
25 | - // NOTE - we might want an isChooseOnePoll in future | |
26 | - // t.true(isChooseOnePoll(fullPollMsg), 'simple (full msg)') | |
27 | - | |
28 | - t.end() | |
29 | -}) |
test/poll/sync/buildChooseOne.test.js | ||
---|---|---|
@@ -1,0 +1,29 @@ | ||
1 | +const test = require('tape') | |
2 | +const ChooseOne = require('../../../poll/sync/buildChooseOne') | |
3 | +const {isPoll, isChooseOnePoll} = require('ssb-poll-schema') | |
4 | + | |
5 | +test('Position - ChooseOne', function (t) { | |
6 | + var invalidPoll = ChooseOne({ | |
7 | + }) | |
8 | + t.false(isPoll(invalidPoll), 'invalid') | |
9 | + | |
10 | + var validPoll = ChooseOne({ | |
11 | + title: 'how many food', | |
12 | + choices: [1, 2, 'three'], | |
13 | + closesAt: new Date().toISOString() | |
14 | + }) | |
15 | + t.true(isPoll(validPoll), 'simple (passes isPoll)') | |
16 | + t.true(isChooseOnePoll(validPoll), 'simple (passes isChooseOnePoll)') | |
17 | + | |
18 | + var fullPollMsg = { | |
19 | + key: '%somekey', | |
20 | + value: { | |
21 | + content: validPoll | |
22 | + } | |
23 | + } | |
24 | + t.true(isPoll(fullPollMsg), 'simple (full msg)') | |
25 | + // NOTE - we might want an isChooseOnePoll in future | |
26 | + // t.true(isChooseOnePoll(fullPollMsg), 'simple (full msg)') | |
27 | + | |
28 | + t.end() | |
29 | +}) |
test/position/async/chooseOne.test.js | ||
---|---|---|
@@ -1,77 +1,0 @@ | ||
1 | -const test = require('tape') | |
2 | -const pull = require('pull-stream') | |
3 | -const pullAsync = require('pull-async') | |
4 | -const ChooseOne = require('../../../position/async/chooseOne')() | |
5 | -const {isPosition} = require('ssb-poll-schema') | |
6 | - | |
7 | -test('Position - ChooseOne', function (t) { | |
8 | - pull( | |
9 | - pullAsync(cb => { | |
10 | - ChooseOne({ | |
11 | - poll: '%t+PhrNxxXkw/jMo6mnwUWfFjJapoPWxzsQoe0Np+nYw=.sha256' | |
12 | - }, cb) | |
13 | - }), | |
14 | - pull.drain((missingChoice) => { | |
15 | - t.false(isPosition(missingChoice), 'missing a choice') | |
16 | - }) | |
17 | - ) | |
18 | - | |
19 | - pull( | |
20 | - pullAsync(cb => { | |
21 | - ChooseOne({ | |
22 | - choice: 0 | |
23 | - }, cb) | |
24 | - }), | |
25 | - pull.drain((missingPoll) => { | |
26 | - t.false(isPosition(missingPoll), 'missing a poll') | |
27 | - }) | |
28 | - ) | |
29 | - | |
30 | - pull( | |
31 | - pullAsync(cb => { | |
32 | - ChooseOne({ | |
33 | - poll: 'dog?', | |
34 | - choice: 0 | |
35 | - }, cb) | |
36 | - }), | |
37 | - pull.drain((missingPoll) => { | |
38 | - t.false(isPosition(missingPoll), 'does not reference a poll') | |
39 | - }) | |
40 | - ) | |
41 | - | |
42 | - pull( | |
43 | - pullAsync(cb => { | |
44 | - ChooseOne({ | |
45 | - poll: '%t+PhrNxxXkw/jMo6mnwUWfFjJapoPWxzsQoe0Np+nYw=.sha256', | |
46 | - choice: 0 | |
47 | - }, cb) | |
48 | - }), | |
49 | - pull.drain((poll) => { | |
50 | - t.true(isPosition(poll), 'simple') | |
51 | - }) | |
52 | - ) | |
53 | - | |
54 | - pull( | |
55 | - pullAsync(cb => { | |
56 | - ChooseOne({ | |
57 | - poll: '%t+PhrNxxXkw/jMo6mnwUWfFjJapoPWxzsQoe0Np+nYw=.sha256', | |
58 | - choice: 0 | |
59 | - }, cb) | |
60 | - }), | |
61 | - pull.map((validPosition) => { | |
62 | - return { | |
63 | - key: '%somekey', | |
64 | - value: { | |
65 | - content: validPosition | |
66 | - } | |
67 | - } | |
68 | - }), | |
69 | - pull.drain((poll) => { | |
70 | - t.true(isPosition(poll), 'simple (full msg)') | |
71 | - t.end() | |
72 | - }) | |
73 | - ) | |
74 | - | |
75 | - // NOTE - we might want an isChooseOnePosition in future | |
76 | - // t.true(isChooseOnePosition(fullPositionMsg), 'simple (full msg)') | |
77 | -}) |
test/position/async/buildChooseOne.test.js | ||
---|---|---|
@@ -1,0 +1,77 @@ | ||
1 | +const test = require('tape') | |
2 | +const pull = require('pull-stream') | |
3 | +const pullAsync = require('pull-async') | |
4 | +const ChooseOne = require('../../../position/async/buildChooseOne')() | |
5 | +const {isPosition} = require('ssb-poll-schema') | |
6 | + | |
7 | +test('Position - ChooseOne', function (t) { | |
8 | + pull( | |
9 | + pullAsync(cb => { | |
10 | + ChooseOne({ | |
11 | + poll: '%t+PhrNxxXkw/jMo6mnwUWfFjJapoPWxzsQoe0Np+nYw=.sha256' | |
12 | + }, cb) | |
13 | + }), | |
14 | + pull.drain((missingChoice) => { | |
15 | + t.false(isPosition(missingChoice), 'missing a choice') | |
16 | + }) | |
17 | + ) | |
18 | + | |
19 | + pull( | |
20 | + pullAsync(cb => { | |
21 | + ChooseOne({ | |
22 | + choice: 0 | |
23 | + }, cb) | |
24 | + }), | |
25 | + pull.drain((missingPoll) => { | |
26 | + t.false(isPosition(missingPoll), 'missing a poll') | |
27 | + }) | |
28 | + ) | |
29 | + | |
30 | + pull( | |
31 | + pullAsync(cb => { | |
32 | + ChooseOne({ | |
33 | + poll: 'dog?', | |
34 | + choice: 0 | |
35 | + }, cb) | |
36 | + }), | |
37 | + pull.drain((missingPoll) => { | |
38 | + t.false(isPosition(missingPoll), 'does not reference a poll') | |
39 | + }) | |
40 | + ) | |
41 | + | |
42 | + pull( | |
43 | + pullAsync(cb => { | |
44 | + ChooseOne({ | |
45 | + poll: '%t+PhrNxxXkw/jMo6mnwUWfFjJapoPWxzsQoe0Np+nYw=.sha256', | |
46 | + choice: 0 | |
47 | + }, cb) | |
48 | + }), | |
49 | + pull.drain((poll) => { | |
50 | + t.true(isPosition(poll), 'simple') | |
51 | + }) | |
52 | + ) | |
53 | + | |
54 | + pull( | |
55 | + pullAsync(cb => { | |
56 | + ChooseOne({ | |
57 | + poll: '%t+PhrNxxXkw/jMo6mnwUWfFjJapoPWxzsQoe0Np+nYw=.sha256', | |
58 | + choice: 0 | |
59 | + }, cb) | |
60 | + }), | |
61 | + pull.map((validPosition) => { | |
62 | + return { | |
63 | + key: '%somekey', | |
64 | + value: { | |
65 | + content: validPosition | |
66 | + } | |
67 | + } | |
68 | + }), | |
69 | + pull.drain((poll) => { | |
70 | + t.true(isPosition(poll), 'simple (full msg)') | |
71 | + t.end() | |
72 | + }) | |
73 | + ) | |
74 | + | |
75 | + // NOTE - we might want an isChooseOnePosition in future | |
76 | + // t.true(isChooseOnePosition(fullPositionMsg), 'simple (full msg)') | |
77 | +}) |
test/position/sync/chooseOneResults.test.js | ||
---|---|---|
@@ -1,209 +1,0 @@ | ||
1 | -const test = require('tape') | |
2 | -const pull = require('pull-stream') | |
3 | -const ChooseOne = require('../../../position/async/chooseOne')() | |
4 | -const ChooseOnePoll = require('../../../poll/sync/chooseOne') | |
5 | -const chooseOneResults = require('../../../position/sync/chooseOneResults') | |
6 | -const {ERROR_POSITION_CHOICE, ERROR_POSITION_LATE} = require('../../../types') | |
7 | - | |
8 | -const pietId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/0=.ed25519' | |
9 | -const mixId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/1=.ed25519' | |
10 | -const mikeyId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/2=.ed25519' | |
11 | -const timmyId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/3=.ed25519' | |
12 | -const tommyId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/4=.ed25519' | |
13 | -const sallyId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/5=.ed25519' | |
14 | - | |
15 | -const poll = '%t+PhrNxxXkw/jMo6mnwUWfFjJapoPWxzsQoe0Np+nYw=.sha256' | |
16 | - | |
17 | -const now = Number(new Date()) | |
18 | - | |
19 | -const validPoll = { | |
20 | - key: '%schwoop', | |
21 | - value: { | |
22 | - content: ChooseOnePoll({ | |
23 | - choices: [1, 2, 'three'], | |
24 | - title: 'how many food', | |
25 | - closesAt: now | |
26 | - }) | |
27 | - } | |
28 | -} | |
29 | - | |
30 | -test('ChooseOneResults - ChooseOneResults', function (t) { | |
31 | - const positions = [ | |
32 | - { value: { content: {choice: 0, poll}, author: pietId } }, | |
33 | - { value: { content: {choice: 0, poll}, author: mixId } }, | |
34 | - { value: { content: {choice: 0, poll}, author: mikeyId } }, | |
35 | - { value: { content: {choice: 1, poll}, author: timmyId } }, | |
36 | - { value: { content: {choice: 1, poll}, author: tommyId } }, | |
37 | - { value: { content: {choice: 2, poll}, author: sallyId } } | |
38 | - ] | |
39 | - | |
40 | - const expected = { | |
41 | - results: [ | |
42 | - { | |
43 | - choice: 1, | |
44 | - voters: { | |
45 | - [pietId]: positions[0], | |
46 | - [mixId]: positions[1], | |
47 | - [mikeyId]: positions[2] | |
48 | - } | |
49 | - }, | |
50 | - { | |
51 | - choice: 2, | |
52 | - voters: { | |
53 | - [timmyId]: positions[3], | |
54 | - [tommyId]: positions[4] | |
55 | - } | |
56 | - }, | |
57 | - { | |
58 | - choice: 'three', | |
59 | - voters: { | |
60 | - [sallyId]: positions[5] | |
61 | - } | |
62 | - } | |
63 | - ], | |
64 | - errors: {} | |
65 | - } | |
66 | - | |
67 | - pull( | |
68 | - pull.values(positions), | |
69 | - pull.asyncMap((fullPosition, cb) => { | |
70 | - ChooseOne(fullPosition.value.content, (err, position) => { | |
71 | - fullPosition.value.content = position | |
72 | - cb(err, fullPosition) | |
73 | - }) | |
74 | - }), | |
75 | - pull.collect(postions => { | |
76 | - const actual = chooseOneResults({positions, poll: validPoll}) | |
77 | - t.deepEqual(actual, expected, 'results are correct') | |
78 | - t.end() | |
79 | - }) | |
80 | - ) | |
81 | -}) | |
82 | - | |
83 | -test('ChooseOneResults - a position stated for an invalid choice index is not counted', function (t) { | |
84 | - const positions = [ | |
85 | - { value: { content: {choice: 3, poll}, author: pietId } } | |
86 | - ] | |
87 | - | |
88 | - pull( | |
89 | - pull.values(positions), | |
90 | - pull.asyncMap((fullPosition, cb) => { | |
91 | - ChooseOne(fullPosition.value.content, (err, position) => { | |
92 | - fullPosition.value.content = position | |
93 | - cb(err, fullPosition) | |
94 | - }) | |
95 | - }), | |
96 | - pull.collect(postions => { | |
97 | - const actual = chooseOneResults({positions, poll: validPoll}) | |
98 | - t.false(actual.results[3], 'invalid vote is not counted') | |
99 | - t.end() | |
100 | - }) | |
101 | - ) | |
102 | -}) | |
103 | - | |
104 | -test('ChooseOneResults - a position stated for an invalid choice index is included in the errors object', function (t) { | |
105 | - const positions = [ | |
106 | - { value: { content: {choice: 3, poll}, author: pietId } } | |
107 | - ] | |
108 | - | |
109 | - pull( | |
110 | - pull.values(positions), | |
111 | - pull.asyncMap((fullPosition, cb) => { | |
112 | - ChooseOne(fullPosition.value.content, (err, position) => { | |
113 | - fullPosition.value.content = position | |
114 | - cb(err, fullPosition) | |
115 | - }) | |
116 | - }), | |
117 | - pull.collect(postions => { | |
118 | - const actual = chooseOneResults({positions, poll: validPoll}) | |
119 | - t.deepEqual(actual.errors[0].type, ERROR_POSITION_CHOICE, 'invalid vote is on error object') | |
120 | - t.end() | |
121 | - }) | |
122 | - ) | |
123 | -}) | |
124 | - | |
125 | -test('ChooseOneResults - A position stated before the closing time of the poll is counted', function (t) { | |
126 | - const positions = [ | |
127 | - { value: { content: {choice: 0, poll}, author: pietId, timestamp: now - 1 } } | |
128 | - ] | |
129 | - | |
130 | - pull( | |
131 | - pull.values(positions), | |
132 | - pull.asyncMap((fullPosition, cb) => { | |
133 | - ChooseOne(fullPosition.value.content, (err, position) => { | |
134 | - fullPosition.value.content = position | |
135 | - cb(err, fullPosition) | |
136 | - }) | |
137 | - }), | |
138 | - pull.collect(postions => { | |
139 | - const actual = chooseOneResults({positions, poll: validPoll}) | |
140 | - t.ok(actual.results[0].voters[pietId], 'valid vote is counted') | |
141 | - t.end() | |
142 | - }) | |
143 | - ) | |
144 | -}) | |
145 | - | |
146 | -test('ChooseOneResults - A position stated after the closing time of the poll is not counted', function (t) { | |
147 | - const positions = [ | |
148 | - { value: { content: {choice: 0, poll}, author: pietId, timestamp: now + 1 } } | |
149 | - ] | |
150 | - | |
151 | - pull( | |
152 | - pull.values(positions), | |
153 | - pull.asyncMap((fullPosition, cb) => { | |
154 | - ChooseOne(fullPosition.value.content, (err, position) => { | |
155 | - fullPosition.value.content = position | |
156 | - cb(err, fullPosition) | |
157 | - }) | |
158 | - }), | |
159 | - pull.collect(postions => { | |
160 | - const actual = chooseOneResults({positions, poll: validPoll}) | |
161 | - t.deepEqual(actual.results[0].voters, {}, 'invalid vote is not counted') | |
162 | - t.end() | |
163 | - }) | |
164 | - ) | |
165 | -}) | |
166 | - | |
167 | -test('ChooseOneResults - A position stated after the closing time of the poll is included in the error object', function (t) { | |
168 | - const positions = [ | |
169 | - { value: { content: {choice: 0, poll}, author: pietId, timestamp: now + 1 } } | |
170 | - ] | |
171 | - | |
172 | - pull( | |
173 | - pull.values(positions), | |
174 | - pull.asyncMap((fullPosition, cb) => { | |
175 | - ChooseOne(fullPosition.value.content, (err, position) => { | |
176 | - fullPosition.value.content = position | |
177 | - cb(err, fullPosition) | |
178 | - }) | |
179 | - }), | |
180 | - pull.collect(postions => { | |
181 | - const actual = chooseOneResults({positions, poll: validPoll}) | |
182 | - t.deepEqual(actual.errors[0].type, ERROR_POSITION_LATE, 'invalid vote is on error object') | |
183 | - t.end() | |
184 | - }) | |
185 | - ) | |
186 | -}) | |
187 | - | |
188 | -test('ChooseOneResults - ChooseOneResults only counts latest vote by an author', function (t) { | |
189 | - const positions = [ | |
190 | - { value: { content: {choice: 2, poll}, author: pietId } }, | |
191 | - { value: { content: {choice: 0, poll}, author: pietId } } | |
192 | - ] | |
193 | - | |
194 | - pull( | |
195 | - pull.values(positions), | |
196 | - pull.asyncMap((fullPosition, cb) => { | |
197 | - ChooseOne(fullPosition.value.content, (err, position) => { | |
198 | - fullPosition.value.content = position | |
199 | - cb(err, fullPosition) | |
200 | - }) | |
201 | - }), | |
202 | - pull.collect(postions => { | |
203 | - const actual = chooseOneResults({positions, poll: validPoll}) | |
204 | - t.false(actual.results[2].voters[pietId], 'old vote is deleted') | |
205 | - t.true(actual.results[0].voters[pietId], 'new vote is counted') | |
206 | - t.end() | |
207 | - }) | |
208 | - ) | |
209 | -}) |
test/position/sync/buildResults.test.js | ||
---|---|---|
@@ -1,0 +1,210 @@ | ||
1 | +const test = require('tape') | |
2 | +const pull = require('pull-stream') | |
3 | +const ChooseOne = require('../../../position/async/buildChooseOne')() | |
4 | +const ChooseOnePoll = require('../../../poll/sync/buildChooseOne') | |
5 | +const chooseOneResults = require('../../../position/sync/buildResults') | |
6 | +const {isPosition, isPoll} = require('ssb-poll-schema') | |
7 | +const {ERROR_POSITION_CHOICE, ERROR_POSITION_LATE} = require('../../../types') | |
8 | + | |
9 | +const pietId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/0=.ed25519' | |
10 | +const mixId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/1=.ed25519' | |
11 | +const mikeyId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/2=.ed25519' | |
12 | +const timmyId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/3=.ed25519' | |
13 | +const tommyId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/4=.ed25519' | |
14 | +const sallyId = '@Mq8D3YC6VdErKQzV3oi2oK5hHSoIwR0hUQr4M46wr/5=.ed25519' | |
15 | + | |
16 | +const poll = '%t+PhrNxxXkw/jMo6mnwUWfFjJapoPWxzsQoe0Np+nYw=.sha256' | |
17 | + | |
18 | +const now = new Date().toISOString() | |
19 | + | |
20 | +const validPoll = { | |
21 | + key: '%t+PhrNxxXkw/jMo6mnwUWfFjJapoPWxzsQoe0Np+nYw=.sha256', | |
22 | + value: { | |
23 | + content: ChooseOnePoll({ | |
24 | + choices: [1, 2, 'three'], | |
25 | + title: 'how many food', | |
26 | + closesAt: now | |
27 | + }) | |
28 | + } | |
29 | +} | |
30 | + | |
31 | +test('ChooseOneResults - ChooseOneResults', function (t) { | |
32 | + const positions = [ | |
33 | + { value: { content: {choice: 0, poll}, author: pietId } }, | |
34 | + { value: { content: {choice: 0, poll}, author: mixId } }, | |
35 | + { value: { content: {choice: 0, poll}, author: mikeyId } }, | |
36 | + { value: { content: {choice: 1, poll}, author: timmyId } }, | |
37 | + { value: { content: {choice: 1, poll}, author: tommyId } }, | |
38 | + { value: { content: {choice: 2, poll}, author: sallyId } } | |
39 | + ] | |
40 | + | |
41 | + const expected = { | |
42 | + results: [ | |
43 | + { | |
44 | + choice: 1, | |
45 | + voters: { | |
46 | + [pietId]: positions[0], | |
47 | + [mixId]: positions[1], | |
48 | + [mikeyId]: positions[2] | |
49 | + } | |
50 | + }, | |
51 | + { | |
52 | + choice: 2, | |
53 | + voters: { | |
54 | + [timmyId]: positions[3], | |
55 | + [tommyId]: positions[4] | |
56 | + } | |
57 | + }, | |
58 | + { | |
59 | + choice: 'three', | |
60 | + voters: { | |
61 | + [sallyId]: positions[5] | |
62 | + } | |
63 | + } | |
64 | + ], | |
65 | + errors: {} | |
66 | + } | |
67 | + | |
68 | + pull( | |
69 | + pull.values(positions), | |
70 | + pull.asyncMap((fullPosition, cb) => { | |
71 | + ChooseOne(fullPosition.value.content, (err, position) => { | |
72 | + fullPosition.value.content = position | |
73 | + cb(err, fullPosition) | |
74 | + }) | |
75 | + }), | |
76 | + pull.collect(postions => { | |
77 | + const actual = chooseOneResults({positions, poll: validPoll}) | |
78 | + t.deepEqual(actual, expected, 'results are correct') | |
79 | + t.end() | |
80 | + }) | |
81 | + ) | |
82 | +}) | |
83 | + | |
84 | +test('ChooseOneResults - a position stated for an invalid choice index is not counted', function (t) { | |
85 | + const positions = [ | |
86 | + { value: { content: {choice: 3, poll}, author: pietId } } | |
87 | + ] | |
88 | + | |
89 | + pull( | |
90 | + pull.values(positions), | |
91 | + pull.asyncMap((fullPosition, cb) => { | |
92 | + ChooseOne(fullPosition.value.content, (err, position) => { | |
93 | + fullPosition.value.content = position | |
94 | + cb(err, fullPosition) | |
95 | + }) | |
96 | + }), | |
97 | + pull.collect(postions => { | |
98 | + const actual = chooseOneResults({positions, poll: validPoll}) | |
99 | + t.false(actual.results[3], 'invalid vote is not counted') | |
100 | + t.end() | |
101 | + }) | |
102 | + ) | |
103 | +}) | |
104 | + | |
105 | +test('ChooseOneResults - a position stated for an invalid choice index is included in the errors object', function (t) { | |
106 | + const positions = [ | |
107 | + { value: { content: {choice: 3, poll}, author: pietId } } | |
108 | + ] | |
109 | + | |
110 | + pull( | |
111 | + pull.values(positions), | |
112 | + pull.asyncMap((fullPosition, cb) => { | |
113 | + ChooseOne(fullPosition.value.content, (err, position) => { | |
114 | + fullPosition.value.content = position | |
115 | + cb(err, fullPosition) | |
116 | + }) | |
117 | + }), | |
118 | + pull.collect(postions => { | |
119 | + const actual = chooseOneResults({positions, poll: validPoll}) | |
120 | + t.deepEqual(actual.errors[0].type, ERROR_POSITION_CHOICE, 'invalid vote is on error object') | |
121 | + t.end() | |
122 | + }) | |
123 | + ) | |
124 | +}) | |
125 | + | |
126 | +test('ChooseOneResults - A position stated before the closing time of the poll is counted', function (t) { | |
127 | + const positions = [ | |
128 | + { value: { content: {choice: 0, poll}, author: pietId, timestamp: now - 1 } } | |
129 | + ] | |
130 | + | |
131 | + pull( | |
132 | + pull.values(positions), | |
133 | + pull.asyncMap((fullPosition, cb) => { | |
134 | + ChooseOne(fullPosition.value.content, (err, position) => { | |
135 | + fullPosition.value.content = position | |
136 | + cb(err, fullPosition) | |
137 | + }) | |
138 | + }), | |
139 | + pull.collect(postions => { | |
140 | + const actual = chooseOneResults({positions, poll: validPoll}) | |
141 | + t.ok(actual.results[0].voters[pietId], 'valid vote is counted') | |
142 | + t.end() | |
143 | + }) | |
144 | + ) | |
145 | +}) | |
146 | + | |
147 | +test('ChooseOneResults - A position stated after the closing time of the poll is not counted', function (t) { | |
148 | + const positions = [ | |
149 | + { value: { content: {choice: 0, poll}, author: pietId, timestamp: now + 1 } } | |
150 | + ] | |
151 | + | |
152 | + pull( | |
153 | + pull.values(positions), | |
154 | + pull.asyncMap((fullPosition, cb) => { | |
155 | + ChooseOne(fullPosition.value.content, (err, position) => { | |
156 | + fullPosition.value.content = position | |
157 | + cb(err, fullPosition) | |
158 | + }) | |
159 | + }), | |
160 | + pull.collect(postions => { | |
161 | + const actual = chooseOneResults({positions, poll: validPoll}) | |
162 | + t.deepEqual(actual.results[0].voters, {}, 'invalid vote is not counted') | |
163 | + t.end() | |
164 | + }) | |
165 | + ) | |
166 | +}) | |
167 | + | |
168 | +test('ChooseOneResults - A position stated after the closing time of the poll is included in the error object', function (t) { | |
169 | + const positions = [ | |
170 | + { value: { content: {choice: 0, poll}, author: pietId, timestamp: now + 1 } } | |
171 | + ] | |
172 | + | |
173 | + pull( | |
174 | + pull.values(positions), | |
175 | + pull.asyncMap((fullPosition, cb) => { | |
176 | + ChooseOne(fullPosition.value.content, (err, position) => { | |
177 | + fullPosition.value.content = position | |
178 | + cb(err, fullPosition) | |
179 | + }) | |
180 | + }), | |
181 | + pull.collect(postions => { | |
182 | + const actual = chooseOneResults({positions, poll: validPoll}) | |
183 | + t.deepEqual(actual.errors[0].type, ERROR_POSITION_LATE, 'invalid vote is on error object') | |
184 | + t.end() | |
185 | + }) | |
186 | + ) | |
187 | +}) | |
188 | + | |
189 | +test('ChooseOneResults - ChooseOneResults only counts latest vote by an author', function (t) { | |
190 | + const positions = [ | |
191 | + { value: { content: {choice: 2, poll}, author: pietId } }, | |
192 | + { value: { content: {choice: 0, poll}, author: pietId } } | |
193 | + ] | |
194 | + | |
195 | + pull( | |
196 | + pull.values(positions), | |
197 | + pull.asyncMap((fullPosition, cb) => { | |
198 | + ChooseOne(fullPosition.value.content, (err, position) => { | |
199 | + fullPosition.value.content = position | |
200 | + cb(err, fullPosition) | |
201 | + }) | |
202 | + }), | |
203 | + pull.collect(postions => { | |
204 | + const actual = chooseOneResults({positions, poll: validPoll}) | |
205 | + t.false(actual.results[2].voters[pietId], 'old vote is deleted') | |
206 | + t.true(actual.results[0].voters[pietId], 'new vote is counted') | |
207 | + t.end() | |
208 | + }) | |
209 | + ) | |
210 | +}) |
Built with git-ssb-web