@@ -1419,4 +1419,322 @@ describe('DecisionService', () => {
14191419 } ) ;
14201420 } ) ;
14211421 } ) ;
1422+
1423+
1424+ describe ( 'forced variation management' , ( ) => {
1425+ it ( 'should return true for a valid forcedVariation in setForcedVariation' , function ( ) {
1426+ const config = createProjectConfig ( cloneDeep ( testData ) ) ;
1427+ const { decisionService } = getDecisionService ( ) ;
1428+
1429+ const didSetVariation = decisionService . setForcedVariation (
1430+ config ,
1431+ 'testExperiment' ,
1432+ 'user1' ,
1433+ 'control'
1434+ ) ;
1435+ expect ( didSetVariation ) . toBe ( true ) ;
1436+ } ) ;
1437+
1438+ it ( 'should return the same variation from getVariation as was set in setVariation' , function ( ) {
1439+ const config = createProjectConfig ( cloneDeep ( testData ) ) ;
1440+ const { decisionService } = getDecisionService ( ) ;
1441+ decisionService . setForcedVariation (
1442+ config ,
1443+ 'testExperiment' ,
1444+ 'user1' ,
1445+ 'control'
1446+ ) ;
1447+
1448+ const variation = decisionService . getForcedVariation ( config , 'testExperiment' , 'user1' ) . result ;
1449+ expect ( variation ) . toBe ( 'control' ) ;
1450+ } ) ;
1451+
1452+ it ( 'should return null from getVariation if no forced variation was set for a valid experimentKey' , function ( ) {
1453+ const config = createProjectConfig ( cloneDeep ( testData ) ) ;
1454+ const { decisionService } = getDecisionService ( ) ;
1455+
1456+ expect ( config . experimentKeyMap [ 'testExperiment' ] ) . toBeDefined ( ) ;
1457+ const variation = decisionService . getForcedVariation ( config , 'testExperiment' , 'user1' ) . result ;
1458+
1459+ expect ( variation ) . toBe ( null ) ;
1460+ } ) ;
1461+
1462+ it ( 'should return null from getVariation for an invalid experimentKey' , function ( ) {
1463+ const config = createProjectConfig ( cloneDeep ( testData ) ) ;
1464+ const { decisionService } = getDecisionService ( ) ;
1465+
1466+ expect ( config . experimentKeyMap [ 'definitely_not_valid_exp_key' ] ) . not . toBeDefined ( ) ;
1467+ const variation = decisionService . getForcedVariation ( config , 'definitely_not_valid_exp_key' , 'user1' ) . result ;
1468+
1469+ expect ( variation ) . toBe ( null ) ;
1470+ } ) ;
1471+
1472+ it ( 'should return null when a forced decision is set on another experiment key' , function ( ) {
1473+ const config = createProjectConfig ( cloneDeep ( testData ) ) ;
1474+ const { decisionService } = getDecisionService ( ) ;
1475+
1476+ decisionService . setForcedVariation ( config , 'testExperiment' , 'user1' , 'control' ) ;
1477+ var variation = decisionService . getForcedVariation ( config , 'testExperimentLaunched' , 'user1' ) . result ;
1478+ expect ( variation ) . toBe ( null ) ;
1479+ } ) ;
1480+
1481+ it ( 'should not set forced variation for an invalid variation key and return false' , function ( ) {
1482+ const config = createProjectConfig ( cloneDeep ( testData ) ) ;
1483+ const { decisionService } = getDecisionService ( ) ;
1484+
1485+ const wasSet = decisionService . setForcedVariation (
1486+ config ,
1487+ 'testExperiment' ,
1488+ 'user1' ,
1489+ 'definitely_not_valid_variation_key'
1490+ ) ;
1491+
1492+ expect ( wasSet ) . toBe ( false ) ;
1493+ const variation = decisionService . getForcedVariation ( config , 'testExperiment' , 'user1' ) . result ;
1494+ expect ( variation ) . toBe ( null ) ;
1495+ } ) ;
1496+
1497+ it ( 'should reset the forcedVariation if null is passed to setForcedVariation' , function ( ) {
1498+ const config = createProjectConfig ( cloneDeep ( testData ) ) ;
1499+ const { decisionService } = getDecisionService ( ) ;
1500+
1501+ const didSetVariation = decisionService . setForcedVariation (
1502+ config ,
1503+ 'testExperiment' ,
1504+ 'user1' ,
1505+ 'control'
1506+ ) ;
1507+
1508+ expect ( didSetVariation ) . toBe ( true ) ;
1509+
1510+ let variation = decisionService . getForcedVariation ( config , 'testExperiment' , 'user1' ) . result ;
1511+ expect ( variation ) . toBe ( 'control' ) ;
1512+
1513+ const didSetVariationAgain = decisionService . setForcedVariation (
1514+ config ,
1515+ 'testExperiment' ,
1516+ 'user1' ,
1517+ null
1518+ ) ;
1519+
1520+ expect ( didSetVariationAgain ) . toBe ( true ) ;
1521+
1522+ variation = decisionService . getForcedVariation ( config , 'testExperiment' , 'user1' ) . result ;
1523+ expect ( variation ) . toBe ( null ) ;
1524+ } ) ;
1525+
1526+ it ( 'should be able to add variations for multiple experiments for one user' , function ( ) {
1527+ const config = createProjectConfig ( cloneDeep ( testData ) ) ;
1528+ const { decisionService } = getDecisionService ( ) ;
1529+
1530+ const didSetVariation1 = decisionService . setForcedVariation (
1531+ config ,
1532+ 'testExperiment' ,
1533+ 'user1' ,
1534+ 'control'
1535+ ) ;
1536+ expect ( didSetVariation1 ) . toBe ( true ) ;
1537+
1538+ const didSetVariation2 = decisionService . setForcedVariation (
1539+ config ,
1540+ 'testExperimentLaunched' ,
1541+ 'user1' ,
1542+ 'controlLaunched'
1543+ ) ;
1544+ expect ( didSetVariation2 ) . toBe ( true ) ;
1545+
1546+ const variation = decisionService . getForcedVariation ( config , 'testExperiment' , 'user1' ) . result ;
1547+ const variation2 = decisionService . getForcedVariation ( config , 'testExperimentLaunched' , 'user1' ) . result ;
1548+ expect ( variation ) . toBe ( 'control' ) ;
1549+ expect ( variation2 ) . toBe ( 'controlLaunched' ) ;
1550+ } ) ;
1551+
1552+ it ( 'should be able to forced variation to same experiment for multiple users' , function ( ) {
1553+ const config = createProjectConfig ( cloneDeep ( testData ) ) ;
1554+ const { decisionService } = getDecisionService ( ) ;
1555+
1556+ const didSetVariation1 = decisionService . setForcedVariation (
1557+ config ,
1558+ 'testExperiment' ,
1559+ 'user1' ,
1560+ 'control'
1561+ ) ;
1562+ expect ( didSetVariation1 ) . toBe ( true ) ;
1563+
1564+ const didSetVariation2 = decisionService . setForcedVariation (
1565+ config ,
1566+ 'testExperiment' ,
1567+ 'user2' ,
1568+ 'variation'
1569+ ) ;
1570+ expect ( didSetVariation2 ) . toBe ( true ) ;
1571+
1572+ const variationControl = decisionService . getForcedVariation ( config , 'testExperiment' , 'user1' ) . result ;
1573+ const variationVariation = decisionService . getForcedVariation ( config , 'testExperiment' , 'user2' ) . result ;
1574+
1575+ expect ( variationControl ) . toBe ( 'control' ) ;
1576+ expect ( variationVariation ) . toBe ( 'variation' ) ;
1577+ } ) ;
1578+
1579+ it ( 'should be able to reset a variation for a user with multiple experiments' , function ( ) {
1580+ const config = createProjectConfig ( cloneDeep ( testData ) ) ;
1581+ const { decisionService } = getDecisionService ( ) ;
1582+
1583+ // Set the first time
1584+ const didSetVariation1 = decisionService . setForcedVariation (
1585+ config ,
1586+ 'testExperiment' ,
1587+ 'user1' ,
1588+ 'control'
1589+ ) ;
1590+ expect ( didSetVariation1 ) . toBe ( true ) ;
1591+
1592+ const didSetVariation2 = decisionService . setForcedVariation (
1593+ config ,
1594+ 'testExperimentLaunched' ,
1595+ 'user1' ,
1596+ 'controlLaunched'
1597+ ) ;
1598+ expect ( didSetVariation2 ) . toBe ( true ) ;
1599+
1600+ let variation1 = decisionService . getForcedVariation ( config , 'testExperiment' , 'user1' ) . result ;
1601+ let variation2 = decisionService . getForcedVariation ( config , 'testExperimentLaunched' , 'user1' ) . result ;
1602+
1603+ expect ( variation1 ) . toBe ( 'control' ) ;
1604+ expect ( variation2 ) . toBe ( 'controlLaunched' ) ;
1605+
1606+ // Reset for one of the experiments
1607+ const didSetVariationAgain = decisionService . setForcedVariation (
1608+ config ,
1609+ 'testExperiment' ,
1610+ 'user1' ,
1611+ 'variation'
1612+ ) ;
1613+ expect ( didSetVariationAgain ) . toBe ( true ) ;
1614+
1615+ variation1 = decisionService . getForcedVariation ( config , 'testExperiment' , 'user1' ) . result ;
1616+ variation2 = decisionService . getForcedVariation ( config , 'testExperimentLaunched' , 'user1' ) . result ;
1617+
1618+ expect ( variation1 ) . toBe ( 'variation' ) ;
1619+ expect ( variation2 ) . toBe ( 'controlLaunched' ) ;
1620+ } ) ;
1621+
1622+ it ( 'should be able to unset a variation for a user with multiple experiments' , function ( ) {
1623+ const config = createProjectConfig ( cloneDeep ( testData ) ) ;
1624+ const { decisionService } = getDecisionService ( ) ;
1625+
1626+ // Set the first time
1627+ const didSetVariation1 = decisionService . setForcedVariation (
1628+ config ,
1629+ 'testExperiment' ,
1630+ 'user1' ,
1631+ 'control'
1632+ ) ;
1633+ expect ( didSetVariation1 ) . toBe ( true ) ;
1634+
1635+ const didSetVariation2 = decisionService . setForcedVariation (
1636+ config ,
1637+ 'testExperimentLaunched' ,
1638+ 'user1' ,
1639+ 'controlLaunched'
1640+ ) ;
1641+ expect ( didSetVariation2 ) . toBe ( true ) ;
1642+
1643+ let variation1 = decisionService . getForcedVariation ( config , 'testExperiment' , 'user1' ) . result ;
1644+ let variation2 = decisionService . getForcedVariation ( config , 'testExperimentLaunched' , 'user1' ) . result ;
1645+
1646+ expect ( variation1 ) . toBe ( 'control' ) ;
1647+ expect ( variation2 ) . toBe ( 'controlLaunched' ) ;
1648+
1649+ // Unset for one of the experiments
1650+ decisionService . setForcedVariation ( config , 'testExperiment' , 'user1' , null ) ;
1651+
1652+ variation1 = decisionService . getForcedVariation ( config , 'testExperiment' , 'user1' ) . result ;
1653+ variation2 = decisionService . getForcedVariation ( config , 'testExperimentLaunched' , 'user1' ) . result ;
1654+
1655+ expect ( variation1 ) . toBe ( null ) ;
1656+ expect ( variation2 ) . toBe ( 'controlLaunched' ) ;
1657+ } ) ;
1658+
1659+ it ( 'should return false for an empty variation key' , function ( ) {
1660+ const config = createProjectConfig ( cloneDeep ( testData ) ) ;
1661+ const { decisionService } = getDecisionService ( ) ;
1662+
1663+ const didSetVariation = decisionService . setForcedVariation ( config , 'testExperiment' , 'user1' , '' ) ;
1664+ expect ( didSetVariation ) . toBe ( false ) ;
1665+ } ) ;
1666+
1667+ it ( 'should return null when a variation was previously set, and that variation no longer exists on the config object' , function ( ) {
1668+ const config = createProjectConfig ( cloneDeep ( testData ) ) ;
1669+ const { decisionService } = getDecisionService ( ) ;
1670+
1671+ const didSetVariation = decisionService . setForcedVariation (
1672+ config ,
1673+ 'testExperiment' ,
1674+ 'user1' ,
1675+ 'control'
1676+ ) ;
1677+ expect ( didSetVariation ) . toBe ( true ) ;
1678+
1679+ const newDatafile = cloneDeep ( testData ) ;
1680+ // Remove 'control' variation from variations, traffic allocation, and datafile forcedVariations.
1681+ newDatafile . experiments [ 0 ] . variations = [
1682+ {
1683+ key : 'variation' ,
1684+ id : '111129' ,
1685+ } ,
1686+ ] ;
1687+ newDatafile . experiments [ 0 ] . trafficAllocation = [
1688+ {
1689+ entityId : '111129' ,
1690+ endOfRange : 9000 ,
1691+ } ,
1692+ ] ;
1693+ newDatafile . experiments [ 0 ] . forcedVariations = {
1694+ user1 : 'variation' ,
1695+ user2 : 'variation' ,
1696+ } ;
1697+ // Now the only variation in testExperiment is 'variation'
1698+ const newConfigObj = createProjectConfig ( newDatafile ) ;
1699+ const forcedVar = decisionService . getForcedVariation ( newConfigObj , 'testExperiment' , 'user1' ) . result ;
1700+ expect ( forcedVar ) . toBe ( null ) ;
1701+ } ) ;
1702+
1703+ it ( "should return null when a variation was previously set, and that variation's experiment no longer exists on the config object" , function ( ) {
1704+ const config = createProjectConfig ( cloneDeep ( testData ) ) ;
1705+ const { decisionService } = getDecisionService ( ) ;
1706+
1707+ const didSetVariation = decisionService . setForcedVariation (
1708+ config ,
1709+ 'testExperiment' ,
1710+ 'user1' ,
1711+ 'control'
1712+ ) ;
1713+ expect ( didSetVariation ) . toBe ( true ) ;
1714+
1715+ const newConfigObj = createProjectConfig ( cloneDeep ( testDataWithFeatures ) ) ;
1716+ const forcedVar = decisionService . getForcedVariation ( newConfigObj , 'testExperiment' , 'user1' ) . result ;
1717+ expect ( forcedVar ) . toBe ( null ) ;
1718+ } ) ;
1719+
1720+ it ( 'should return false from setForcedVariation and not set for invalid experiment key' , function ( ) {
1721+ const config = createProjectConfig ( cloneDeep ( testData ) ) ;
1722+ const { decisionService } = getDecisionService ( ) ;
1723+
1724+ const didSetVariation = decisionService . setForcedVariation (
1725+ config ,
1726+ 'definitelyNotAValidExperimentKey' ,
1727+ 'user1' ,
1728+ 'control'
1729+ ) ;
1730+ expect ( didSetVariation ) . toBe ( false ) ;
1731+
1732+ const variation = decisionService . getForcedVariation (
1733+ config ,
1734+ 'definitelyNotAValidExperimentKey' ,
1735+ 'user1'
1736+ ) . result ;
1737+ expect ( variation ) . toBe ( null ) ;
1738+ } ) ;
1739+ } ) ;
14221740} ) ;
0 commit comments