commit
						a794bfdd3e
					
				|  | @ -1,113 +0,0 @@ | |||
| /* | ||||
| Copyright 2016 OpenMarket Ltd | ||||
| Copyright 2019 The Matrix.org Foundation C.I.C. | ||||
| 
 | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
| 
 | ||||
|     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| 
 | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| /** | ||||
|  * For two objects of the form { key: [val1, val2, val3] }, work out the added/removed | ||||
|  * values. Entirely new keys will result in the entire value array being added. | ||||
|  * @param {Object} before | ||||
|  * @param {Object} after | ||||
|  * @return {Object[]} An array of objects with the form: | ||||
|  * { key: $KEY, val: $VALUE, place: "add|del" } | ||||
|  */ | ||||
| export function getKeyValueArrayDiffs(before, after) { | ||||
|     const results = []; | ||||
|     const delta = {}; | ||||
|     Object.keys(before).forEach(function(beforeKey) { | ||||
|         delta[beforeKey] = delta[beforeKey] || 0; // init to 0 initially
 | ||||
|         delta[beforeKey]--; // keys present in the past have -ve values
 | ||||
|     }); | ||||
|     Object.keys(after).forEach(function(afterKey) { | ||||
|         delta[afterKey] = delta[afterKey] || 0; // init to 0 initially
 | ||||
|         delta[afterKey]++; // keys present in the future have +ve values
 | ||||
|     }); | ||||
| 
 | ||||
|     Object.keys(delta).forEach(function(muxedKey) { | ||||
|         switch (delta[muxedKey]) { | ||||
|             case 1: // A new key in after
 | ||||
|                 after[muxedKey].forEach(function(afterVal) { | ||||
|                     results.push({ place: "add", key: muxedKey, val: afterVal }); | ||||
|                 }); | ||||
|                 break; | ||||
|             case -1: // A before key was removed
 | ||||
|                 before[muxedKey].forEach(function(beforeVal) { | ||||
|                     results.push({ place: "del", key: muxedKey, val: beforeVal }); | ||||
|                 }); | ||||
|                 break; | ||||
|             case 0: {// A mix of added/removed keys
 | ||||
|                 // compare old & new vals
 | ||||
|                 const itemDelta = {}; | ||||
|                 before[muxedKey].forEach(function(beforeVal) { | ||||
|                     itemDelta[beforeVal] = itemDelta[beforeVal] || 0; | ||||
|                     itemDelta[beforeVal]--; | ||||
|                 }); | ||||
|                 after[muxedKey].forEach(function(afterVal) { | ||||
|                     itemDelta[afterVal] = itemDelta[afterVal] || 0; | ||||
|                     itemDelta[afterVal]++; | ||||
|                 }); | ||||
| 
 | ||||
|                 Object.keys(itemDelta).forEach(function(item) { | ||||
|                     if (itemDelta[item] === 1) { | ||||
|                         results.push({ place: "add", key: muxedKey, val: item }); | ||||
|                     } else if (itemDelta[item] === -1) { | ||||
|                         results.push({ place: "del", key: muxedKey, val: item }); | ||||
|                     } else { | ||||
|                         // itemDelta of 0 means it was unchanged between before/after
 | ||||
|                     } | ||||
|                 }); | ||||
|                 break; | ||||
|             } | ||||
|             default: | ||||
|                 console.error("Calculated key delta of " + delta[muxedKey] + " - this should never happen!"); | ||||
|                 break; | ||||
|         } | ||||
|     }); | ||||
| 
 | ||||
|     return results; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Shallow-compare two objects for equality: each key and value must be identical | ||||
|  * @param {Object} objA First object to compare against the second | ||||
|  * @param {Object} objB Second object to compare against the first | ||||
|  * @return {boolean} whether the two objects have same key=values | ||||
|  */ | ||||
| export function shallowEqual(objA, objB) { | ||||
|     if (objA === objB) { | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     if (typeof objA !== 'object' || objA === null || | ||||
|           typeof objB !== 'object' || objB === null) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     const keysA = Object.keys(objA); | ||||
|     const keysB = Object.keys(objB); | ||||
| 
 | ||||
|     if (keysA.length !== keysB.length) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     for (let i = 0; i < keysA.length; i++) { | ||||
|         const key = keysA[i]; | ||||
|         if (!objB.hasOwnProperty(key) || objA[key] !== objB[key]) { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
|  | @ -1,51 +0,0 @@ | |||
| /* | ||||
| Copyright 2018 New Vector Ltd | ||||
| 
 | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
| 
 | ||||
|     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| 
 | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| import SdkConfig from './SdkConfig'; | ||||
| import {hashCode} from './utils/FormattingUtils'; | ||||
| 
 | ||||
| export function phasedRollOutExpiredForUser(username, feature, now, rollOutConfig = SdkConfig.get().phasedRollOut) { | ||||
|     if (!rollOutConfig) { | ||||
|         console.log(`no phased rollout configuration, so enabling ${feature}`); | ||||
|         return true; | ||||
|     } | ||||
|     const featureConfig = rollOutConfig[feature]; | ||||
|     if (!featureConfig) { | ||||
|         console.log(`${feature} doesn't have phased rollout configured, so enabling`); | ||||
|         return true; | ||||
|     } | ||||
|     if (!Number.isFinite(featureConfig.offset) || !Number.isFinite(featureConfig.period)) { | ||||
|         console.error(`phased rollout of ${feature} is misconfigured, ` + | ||||
|             `offset and/or period are not numbers, so disabling`, featureConfig); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     const hash = hashCode(username); | ||||
|     //ms -> min, enable users at minute granularity
 | ||||
|     const bucketRatio = 1000 * 60; | ||||
|     const bucketCount = featureConfig.period / bucketRatio; | ||||
|     const userBucket = hash % bucketCount; | ||||
|     const userMs = userBucket * bucketRatio; | ||||
|     const enableAt = featureConfig.offset + userMs; | ||||
|     const result = now >= enableAt; | ||||
|     const bucketStr = `(bucket ${userBucket}/${bucketCount})`; | ||||
|     if (result) { | ||||
|         console.log(`${feature} enabled for ${username} ${bucketStr}`); | ||||
|     } else { | ||||
|         console.log(`${feature} will be enabled for ${username} in ${Math.ceil((enableAt - now)/1000)}s ${bucketStr}`); | ||||
|     } | ||||
|     return result; | ||||
| } | ||||
|  | @ -38,7 +38,6 @@ import CallHandler from '../../CallHandler'; | |||
| import dis from '../../dispatcher/dispatcher'; | ||||
| import Tinter from '../../Tinter'; | ||||
| import rateLimitedFunc from '../../ratelimitedfunc'; | ||||
| import * as ObjectUtils from '../../ObjectUtils'; | ||||
| import * as Rooms from '../../Rooms'; | ||||
| import eventSearch, { searchPagination } from '../../Searching'; | ||||
| import { isOnlyCtrlOrCmdIgnoreShiftKeyEvent, Key } from '../../Keyboard'; | ||||
|  | @ -80,6 +79,7 @@ import Notifier from "../../Notifier"; | |||
| import { showToast as showNotificationsToast } from "../../toasts/DesktopNotificationsToast"; | ||||
| import { RoomNotificationStateStore } from "../../stores/notifications/RoomNotificationStateStore"; | ||||
| import { Container, WidgetLayoutStore } from "../../stores/widgets/WidgetLayoutStore"; | ||||
| import { objectHasDiff } from "../../utils/objects"; | ||||
| 
 | ||||
| const DEBUG = false; | ||||
| let debuglog = function(msg: string) {}; | ||||
|  | @ -523,8 +523,7 @@ export default class RoomView extends React.Component<IProps, IState> { | |||
|     } | ||||
| 
 | ||||
|     shouldComponentUpdate(nextProps, nextState) { | ||||
|         return (!ObjectUtils.shallowEqual(this.props, nextProps) || | ||||
|                 !ObjectUtils.shallowEqual(this.state, nextState)); | ||||
|         return (objectHasDiff(this.props, nextProps) || objectHasDiff(this.state, nextState)); | ||||
|     } | ||||
| 
 | ||||
|     componentDidUpdate() { | ||||
|  |  | |||
|  | @ -26,7 +26,6 @@ import {EventTimeline} from "matrix-js-sdk"; | |||
| import * as Matrix from "matrix-js-sdk"; | ||||
| import { _t } from '../../languageHandler'; | ||||
| import {MatrixClientPeg} from "../../MatrixClientPeg"; | ||||
| import * as ObjectUtils from "../../ObjectUtils"; | ||||
| import UserActivity from "../../UserActivity"; | ||||
| import Modal from "../../Modal"; | ||||
| import dis from "../../dispatcher/dispatcher"; | ||||
|  | @ -37,6 +36,7 @@ import shouldHideEvent from '../../shouldHideEvent'; | |||
| import EditorStateTransfer from '../../utils/EditorStateTransfer'; | ||||
| import {haveTileForEvent} from "../views/rooms/EventTile"; | ||||
| import {UIFeature} from "../../settings/UIFeature"; | ||||
| import {objectHasDiff} from "../../utils/objects"; | ||||
| 
 | ||||
| const PAGINATE_SIZE = 20; | ||||
| const INITIAL_SIZE = 20; | ||||
|  | @ -261,7 +261,7 @@ class TimelinePanel extends React.Component { | |||
|     } | ||||
| 
 | ||||
|     shouldComponentUpdate(nextProps, nextState) { | ||||
|         if (!ObjectUtils.shallowEqual(this.props, nextProps)) { | ||||
|         if (objectHasDiff(this.props, nextProps)) { | ||||
|             if (DEBUG) { | ||||
|                 console.group("Timeline.shouldComponentUpdate: props change"); | ||||
|                 console.log("props before:", this.props); | ||||
|  | @ -271,7 +271,7 @@ class TimelinePanel extends React.Component { | |||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         if (!ObjectUtils.shallowEqual(this.state, nextState)) { | ||||
|         if (objectHasDiff(this.state, nextState)) { | ||||
|             if (DEBUG) { | ||||
|                 console.group("Timeline.shouldComponentUpdate: state change"); | ||||
|                 console.log("state before:", this.state); | ||||
|  |  | |||
|  | @ -1,41 +0,0 @@ | |||
| /* | ||||
| Copyright 2017 Vector Creations Ltd | ||||
| 
 | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
| 
 | ||||
|     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| 
 | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| import React from 'react'; | ||||
| import * as sdk from '../../../index'; | ||||
| import PropTypes from 'prop-types'; | ||||
| import { _t } from '../../../languageHandler'; | ||||
| import {Action} from "../../../dispatcher/actions"; | ||||
| 
 | ||||
| const RoomDirectoryButton = function(props) { | ||||
|     const ActionButton = sdk.getComponent('elements.ActionButton'); | ||||
|     return ( | ||||
|         <ActionButton action={Action.ViewRoomDirectory} | ||||
|             mouseOverAction={props.callout ? "callout_room_directory" : null} | ||||
|             label={_t("Room directory")} | ||||
|             iconPath={require("../../../../res/img/icons-directory.svg")} | ||||
|             size={props.size} | ||||
|             tooltip={props.tooltip} | ||||
|         /> | ||||
|     ); | ||||
| }; | ||||
| 
 | ||||
| RoomDirectoryButton.propTypes = { | ||||
|     size: PropTypes.string, | ||||
|     tooltip: PropTypes.bool, | ||||
| }; | ||||
| 
 | ||||
| export default RoomDirectoryButton; | ||||
|  | @ -1,40 +0,0 @@ | |||
| /* | ||||
| Copyright 2017 Vector Creations Ltd | ||||
| 
 | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
| 
 | ||||
|     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| 
 | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| import React from 'react'; | ||||
| import * as sdk from '../../../index'; | ||||
| import PropTypes from 'prop-types'; | ||||
| import { _t } from '../../../languageHandler'; | ||||
| 
 | ||||
| const StartChatButton = function(props) { | ||||
|     const ActionButton = sdk.getComponent('elements.ActionButton'); | ||||
|     return ( | ||||
|         <ActionButton action="view_create_chat" | ||||
|             mouseOverAction={props.callout ? "callout_start_chat" : null} | ||||
|             label={_t("Start chat")} | ||||
|             iconPath={require("../../../../res/img/icons-people.svg")} | ||||
|             size={props.size} | ||||
|             tooltip={props.tooltip} | ||||
|         /> | ||||
|     ); | ||||
| }; | ||||
| 
 | ||||
| StartChatButton.propTypes = { | ||||
|     size: PropTypes.string, | ||||
|     tooltip: PropTypes.bool, | ||||
| }; | ||||
| 
 | ||||
| export default StartChatButton; | ||||
|  | @ -1,63 +0,0 @@ | |||
| /* | ||||
| Copyright 2017 New Vector Ltd | ||||
| 
 | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
| 
 | ||||
|     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| 
 | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| import React from 'react'; | ||||
| import PropTypes from 'prop-types'; | ||||
| import TintableSvg from './TintableSvg'; | ||||
| import AccessibleButton from './AccessibleButton'; | ||||
| 
 | ||||
| export default class TintableSvgButton extends React.Component { | ||||
|     constructor(props) { | ||||
|         super(props); | ||||
|     } | ||||
| 
 | ||||
|     render() { | ||||
|         let classes = "mx_TintableSvgButton"; | ||||
|         if (this.props.className) { | ||||
|             classes += " " + this.props.className; | ||||
|         } | ||||
|         return ( | ||||
|             <span | ||||
|                 width={this.props.width} | ||||
|                 height={this.props.height} | ||||
|                 className={classes}> | ||||
|                 <TintableSvg | ||||
|                     src={this.props.src} | ||||
|                     width={this.props.width} | ||||
|                     height={this.props.height} | ||||
|                 ></TintableSvg> | ||||
|                 <AccessibleButton | ||||
|                     onClick={this.props.onClick} | ||||
|                     element='span' | ||||
|                     title={this.props.title} | ||||
|                 /> | ||||
|             </span> | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| TintableSvgButton.propTypes = { | ||||
|     src: PropTypes.string, | ||||
|     title: PropTypes.string, | ||||
|     className: PropTypes.string, | ||||
|     width: PropTypes.string.isRequired, | ||||
|     height: PropTypes.string.isRequired, | ||||
|     onClick: PropTypes.func, | ||||
| }; | ||||
| 
 | ||||
| TintableSvgButton.defaultProps = { | ||||
|     onClick: function() {}, | ||||
| }; | ||||
|  | @ -19,7 +19,6 @@ import {MatrixClientPeg} from "../../../MatrixClientPeg"; | |||
| import { Room } from 'matrix-js-sdk/src/models/room' | ||||
| import * as sdk from '../../../index'; | ||||
| import dis from "../../../dispatcher/dispatcher"; | ||||
| import * as ObjectUtils from '../../../ObjectUtils'; | ||||
| import AppsDrawer from './AppsDrawer'; | ||||
| import { _t } from '../../../languageHandler'; | ||||
| import classNames from 'classnames'; | ||||
|  | @ -29,6 +28,7 @@ import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; | |||
| import {UIFeature} from "../../../settings/UIFeature"; | ||||
| import { ResizeNotifier } from "../../../utils/ResizeNotifier"; | ||||
| import CallViewForRoom from '../voip/CallViewForRoom'; | ||||
| import {objectHasDiff} from "../../../utils/objects"; | ||||
| 
 | ||||
| interface IProps { | ||||
|     // js-sdk room object
 | ||||
|  | @ -89,8 +89,7 @@ export default class AuxPanel extends React.Component<IProps, IState> { | |||
|     } | ||||
| 
 | ||||
|     shouldComponentUpdate(nextProps, nextState) { | ||||
|         return (!ObjectUtils.shallowEqual(this.props, nextProps) || | ||||
|                 !ObjectUtils.shallowEqual(this.state, nextState)); | ||||
|         return objectHasDiff(this.props, nextProps) || objectHasDiff(this.state, nextState); | ||||
|     } | ||||
| 
 | ||||
|     componentDidUpdate(prevProps, prevState) { | ||||
|  |  | |||
|  | @ -32,13 +32,13 @@ import {EventStatus} from 'matrix-js-sdk'; | |||
| import {formatTime} from "../../../DateUtils"; | ||||
| import {MatrixClientPeg} from '../../../MatrixClientPeg'; | ||||
| import {ALL_RULE_TYPES} from "../../../mjolnir/BanList"; | ||||
| import * as ObjectUtils from "../../../ObjectUtils"; | ||||
| import MatrixClientContext from "../../../contexts/MatrixClientContext"; | ||||
| import {E2E_STATE} from "./E2EIcon"; | ||||
| import {toRem} from "../../../utils/units"; | ||||
| import {WidgetType} from "../../../widgets/WidgetType"; | ||||
| import RoomAvatar from "../avatars/RoomAvatar"; | ||||
| import {WIDGET_LAYOUT_EVENT_TYPE} from "../../../stores/widgets/WidgetLayoutStore"; | ||||
| import {objectHasDiff} from "../../../utils/objects"; | ||||
| 
 | ||||
| const eventTileTypes = { | ||||
|     'm.room.message': 'messages.MessageEvent', | ||||
|  | @ -294,7 +294,7 @@ export default class EventTile extends React.Component { | |||
|     } | ||||
| 
 | ||||
|     shouldComponentUpdate(nextProps, nextState) { | ||||
|         if (!ObjectUtils.shallowEqual(this.state, nextState)) { | ||||
|         if (objectHasDiff(this.state, nextState)) { | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1933,7 +1933,6 @@ | |||
|     "Please provide a room address": "Please provide a room address", | ||||
|     "This address is available to use": "This address is available to use", | ||||
|     "This address is already in use": "This address is already in use", | ||||
|     "Room directory": "Room directory", | ||||
|     "Server Options": "Server Options", | ||||
|     "You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use Element with an existing Matrix account on a different homeserver.": "You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use Element with an existing Matrix account on a different homeserver.", | ||||
|     "Join millions for free on the largest public server": "Join millions for free on the largest public server", | ||||
|  |  | |||
|  | @ -211,7 +211,7 @@ export class Algorithm extends EventEmitter { | |||
|         } | ||||
| 
 | ||||
|         // When we do have a room though, we expect to be able to find it
 | ||||
|         let tag = this.roomIdsToTags[val.roomId][0]; | ||||
|         let tag = this.roomIdsToTags[val.roomId]?.[0]; | ||||
|         if (!tag) throw new Error(`${val.roomId} does not belong to a tag and cannot be sticky`); | ||||
| 
 | ||||
|         // We specifically do NOT use the ordered rooms set as it contains the sticky room, which
 | ||||
|  |  | |||
|  | @ -14,7 +14,7 @@ See the License for the specific language governing permissions and | |||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| import { arrayDiff, arrayHasDiff, arrayMerge, arrayUnion } from "./arrays"; | ||||
| import { arrayDiff, arrayMerge, arrayUnion } from "./arrays"; | ||||
| 
 | ||||
| type ObjectExcluding<O extends {}, P extends (keyof O)[]> = {[k in Exclude<keyof O, P[number]>]: O[k]}; | ||||
| 
 | ||||
|  | @ -86,11 +86,13 @@ export function objectShallowClone<O extends {}>(a: O, propertyCloner?: (k: keyo | |||
|  * @returns True if there's a difference between the objects, false otherwise | ||||
|  */ | ||||
| export function objectHasDiff<O extends {}>(a: O, b: O): boolean { | ||||
|     if (a === b) return false; | ||||
|     const aKeys = Object.keys(a); | ||||
|     const bKeys = Object.keys(b); | ||||
|     if (arrayHasDiff(aKeys, bKeys)) return true; | ||||
| 
 | ||||
|     const possibleChanges = arrayUnion(aKeys, bKeys); | ||||
|     // if the amalgamation of both sets of keys has the a different length to the inputs then there must be a change
 | ||||
|     if (possibleChanges.length !== aKeys.length) return true; | ||||
| 
 | ||||
|     return possibleChanges.some(k => a[k] !== b[k]); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,71 +0,0 @@ | |||
| /* | ||||
| Copyright 2018 New Vector Ltd | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| import {phasedRollOutExpiredForUser} from '../src/PhasedRollOut'; | ||||
| 
 | ||||
| const OFFSET = 6000000; | ||||
| // phasedRollOutExpiredForUser enables users in bucks of 1 minute
 | ||||
| const MS_IN_MINUTE = 60 * 1000; | ||||
| 
 | ||||
| describe('PhasedRollOut', function() { | ||||
|     it('should return true if phased rollout is not configured', function() { | ||||
|         expect(phasedRollOutExpiredForUser("@user:hs", "feature_test", 0, null)).toBeTruthy(); | ||||
|     }); | ||||
| 
 | ||||
|     it('should return true if phased rollout feature is not configured', function() { | ||||
|         expect(phasedRollOutExpiredForUser("@user:hs", "feature_test", 0, { | ||||
|             "feature_other": {offset: 0, period: 0}, | ||||
|         })).toBeTruthy(); | ||||
|     }); | ||||
| 
 | ||||
|     it('should return false if phased rollout for feature is misconfigured', function() { | ||||
|         expect(phasedRollOutExpiredForUser("@user:hs", "feature_test", 0, { | ||||
|             "feature_test": {}, | ||||
|         })).toBeFalsy(); | ||||
|     }); | ||||
| 
 | ||||
|     it("should return false if phased rollout hasn't started yet", function() { | ||||
|         expect(phasedRollOutExpiredForUser("@user:hs", "feature_test", 5000000, { | ||||
|             "feature_test": {offset: OFFSET, period: MS_IN_MINUTE}, | ||||
|         })).toBeFalsy(); | ||||
|     }); | ||||
| 
 | ||||
|     it("should start to return true in bucket 2/10 for '@user:hs'", function() { | ||||
|         expect(phasedRollOutExpiredForUser("@user:hs", "feature_test", | ||||
|             OFFSET + (MS_IN_MINUTE * 2) - 1, { | ||||
|             "feature_test": {offset: OFFSET, period: MS_IN_MINUTE * 10}, | ||||
|         })).toBeFalsy(); | ||||
|         expect(phasedRollOutExpiredForUser("@user:hs", "feature_test", | ||||
|             OFFSET + (MS_IN_MINUTE * 2), { | ||||
|             "feature_test": {offset: OFFSET, period: MS_IN_MINUTE * 10}, | ||||
|         })).toBeTruthy(); | ||||
|     }); | ||||
| 
 | ||||
|     it("should start to return true in bucket 4/10 for 'alice@other-hs'", function() { | ||||
|         expect(phasedRollOutExpiredForUser("alice@other-hs", "feature_test", | ||||
|             OFFSET + (MS_IN_MINUTE * 4) - 1, { | ||||
|             "feature_test": {offset: OFFSET, period: MS_IN_MINUTE * 10}, | ||||
|         })).toBeFalsy(); | ||||
|         expect(phasedRollOutExpiredForUser("alice@other-hs", "feature_test", | ||||
|             OFFSET + (MS_IN_MINUTE * 4), { | ||||
|             "feature_test": {offset: OFFSET, period: MS_IN_MINUTE * 10}, | ||||
|         })).toBeTruthy(); | ||||
|     }); | ||||
| 
 | ||||
|     it("should return true after complete rollout period'", function() { | ||||
|         expect(phasedRollOutExpiredForUser("user:hs", "feature_test", | ||||
|             OFFSET + (MS_IN_MINUTE * 20), { | ||||
|             "feature_test": {offset: OFFSET, period: MS_IN_MINUTE * 10}, | ||||
|         })).toBeTruthy(); | ||||
|     }); | ||||
| }); | ||||
		Loading…
	
		Reference in New Issue
	
	 Michael Telatynski
						Michael Telatynski