特性GateJs 客户端
Statsig js-lite客户端的地图集包.
使用量
import FeatureGateJsClient from '@atlaskit/feature-gate-js-client';
这个仓库是干什么的?
Js客户端覆盖前端功能门使用大小写. 这个客户端是模拟靴子陷阱 特性门值来自后端,不接收活更新.
客户用户
安装
客户可以从国家防范机制档案库中调取.
yarn add @atlaskit/feature-gate-js-client
初始化
客户端在尝试使用前必须初始化,否则会出错.
初始化客户有三种方式:
1. 默认初始化机制
这将通过调用特性旗服务来初始化客户端 (单位:千美元)fx3 请检查url=值 (帮助)),并用返回的值将客户端拖入。 如果 客户端以任何理由未能初始化, 包括获取时间超过2秒 值,将使用默认值.
import FeatureGates, {
FeatureGateEnvironment,
FeatureGateProducts,
PerimeterType,
} from '@atlaskit/feature-gate-js-client';
try {
await FeatureGates.initialize(
{
// This is an fx3 api key used to fetch the feature flag values.
// Supported keys found at go/fx3/resources/api-keys
apiKey: 'client-test',
// This is the environment that you are operating in, targeting rules can target specific environments
environment: FeatureGateEnvironment.Production,
// This will be used to filter data from Statsig to only one target app.
// View [doc](https://hello.atlassian.net/wiki/spaces/MEASURE/pages/2955970231/How-to+Use+TargetApps+in+Statsig)
// for details on using targetApp.
targetApp: 'jira_web',
// [Optional] Default is 2000ms
// This is the fetch timeout used for requests to feature-flag-service to get values to bootstrap the client.
// The higher this value the longer your application will need to wait to render if you block on client initialization
// Too low and your application will be more likely to fallback on default values
fetchTimeoutMs: 1000,
// [Optional] Default is false
// This is a boolean to indicate whether to use the `gateway/api` url for the request to feature flag service.
// Note that this option takes precendence over the environment and perimeter options in building the url.
// To be used for applications with strict cross-origin policies, as it will keep all requests to the same origin.
useGatewayUrl: true,
// [Optional] Default is false
// Whether to include flags served by the Feature Flag Platform (FFP). When true, values are fetched from the
// feature-flag-service `/api/v1/evalFlags` endpoint instead of `/api/v2/frontend/experimentValues`.
// Each flag is then served by the platform the service assigns it to. When false, FFP is treated as disabled.
includeFfpFlags: false,
// [Optional] Must be one of the strings from the exported enum PerimeterType.
// If provided, will build base url for the `feature-flag-service` based on environment and perimeter type, and
// will disable all logging to Statsig in perimeters where it is prohibited..
perimeter: PerimeterType.FEDRAMP_MODERATE,
},
{
// These are expected identifiers, you must provide them if they are relevant to your product and will be added to exposures events
analyticsAnonymousId: '<analyticsAnonymousId>',
atlassianAccountId: '<aaid>',
atlassianOrgId: '<orgid>',
tenantId: '<tenantid>',
transactionAccountId: '<transactionAccountId>',
trelloUserId: '<trelloUserId>',
trelloWorkspaceId: '<trelloWorkspaceId>',
},
{
// These are additional custom attributes that can be used for targeting and will be added to exposure events
exampleCustomAttribute: '<attributeValue>',
},
);
} catch (err) {
console.error('Failed to initialize FeatureGates client.', err);
}
如果您的应用程序有登录流程或其他机制,使用户能够
在会话中更改,然后可以使用 updateUser 方法应用此更改。 这个
此方法的签名几乎与 initialize,但仅需要选项
用于获取新的一组值.
重要性:调用这种方法将完全重新启用客户端并使用一对新的旗帜. 完成后,您需要重新发送整个页面,以确保所有东西都能接上 新旗帜值 。 您应该避免频繁使用它,因为它对用户有影响 经历.
import FeatureGates, {
FeatureGateEnvironment,
FeatureGateProducts,
PerimeterType,
} from '@atlaskit/feature-gate-js-client';
try {
await FeatureGates.updateUser(
{
// This is an fx3 api key used to fetch the feature flag values.
// Supported keys found at go/fx3/resources/api-keys
apiKey: 'client-test',
// This is the environment that you are operating in, targeting rules can target specific environments
environment: FeatureGateEnvironment.Production,
// [Optional] Default is 2000ms
// This is the fetch timeout used for requests to feature-flag-service to get values to bootstrap the client.
fetchTimeoutMs: 1000,
// [Optional] Default is false
// This is a boolean to indicate whether to use the `gateway/api` url for the request to feature flag service.
// Note that this option takes precendence over the environment and perimeter options in building the url.
// To be used for applications with strict cross-origin policies, as it will keep all requests to the same origin.
useGatewayUrl: true,
// [Optional] Default is false
// Whether to include flags served by the Feature Flag Platform (FFP). When true, values are fetched from the
// feature-flag-service `/api/v1/evalFlags` endpoint instead of `/api/v2/frontend/experimentValues`.
// Each flag is then served by the platform the service assigns it to. When false, FFP is treated as disabled.
includeFfpFlags: false,
// [Optional] Default is COMMERCIAL. Must be one of the values from the exported enum PerimeterType.
// If provided, will build base url for the `feature-flag-service` based on environment and perimeter type, and
// will disable all logging to Statsig in perimeters where it is prohibited.
perimeter: PerimeterType.FEDRAMP_MODERATE,
},
{
// These are expected identifiers, you must provide them if they are relevant to your product and will be added to exposures events
analyticsAnonymousId: '<analyticsAnonymousId>',
atlassianAccountId: '<aaid>',
atlassianOrgId: '<orgid>',
tenantId: '<tenantid>',
transactionAccountId: '<transactionAccountId>',
trelloUserId: '<trelloUserId>',
trelloWorkspaceId: '<trelloWorkspaceId>',
},
{
// These are additional custom attributes that can be used for targeting and will be added to exposure events
exampleCustomAttribute: '<attributeValue>',
},
);
} catch (err) {
console.error('Failed to update the FeatureGates user.', err);
}
2. 从价值入手
您必须使用我们一个包装后端客户端获取自己的值( 也可以在此找到 ) repo)并提供给此前端客户端
import FeatureGates, {
FeatureGateEnvironment,
FeatureGateProducts,
} from '@atlaskit/feature-gate-js-client';
try {
await FeatureGates.initializeFromValues(
{
// [Optional] This should come directly from a backend or service from the Statsig.getClientInitializeResponse(user) call
// Or supplied from the statsig UI
// Should be provided if it is available. It is optional so initialisation can still occur if the request to fetch the key fails
// If not provided, a default string will be used but exposure event data will not be sent back to Statsig
sdkKey: 'client-test',
// This is the environment that you are operating in, targeting rules can target specific environments
environment: FeatureGateEnvironment.Production,
// This will be used to filter config data relevant to the listed products
products: [FeatureGateProducts.Jira],
},
{
// These are expected identifiers, you must provide them if they are relevant to your product and will be added to exposures events
analyticsAnonymousId: '<analyticsAnonymousId>',
atlassianAccountId: '<aaid>',
atlassianOrgId: '<orgid>',
tenantId: '<tenantid>',
transactionAccountId: '<transactionAccountId>',
trelloUserId: '<trelloUserId>',
trelloWorkspaceId: '<trelloWorkspaceId>',
},
{
// These are additional custom attributes that will be added to exposure events
exampleCustomAttribute: '<attributeValue>',
},
// This should come directly from a backend or service from the Statsig.getClientInitializeResponse(user) call
initializeValues,
);
} catch (err) {
console.error('Failed to initialize FeatureGates client.', err);
}
如果您的应用程序有登录流程或其他机制,使用户能够
在会话中更改,然后可以使用 updateUserWithValues 方法应用此更改.
这种方法的签名几乎与 initializeFromValues,但是它没有
需要任何选项.
重要性:调用这种方法将完全重新启用客户端并使用一对新的旗帜. 完成后,您需要重新发送整个页面,以确保所有东西都能接上 新旗帜值 。 您应该避免频繁使用它,因为它对用户有影响 经历.
import FeatureGates, {
FeatureGateEnvironment,
FeatureGateProducts,
} from '@atlaskit/feature-gate-js-client';
try {
await FeatureGates.updateWithValues(
{
// These are expected identifiers, you must provide them if they are relevant to your product and will be added to exposures events
analyticsAnonymousId: '<analyticsAnonymousId>',
atlassianAccountId: '<aaid>',
atlassianOrgId: '<orgid>',
tenantId: '<tenantid>',
transactionAccountId: '<transactionAccountId>',
trelloUserId: '<trelloUserId>',
trelloWorkspaceId: '<trelloWorkspaceId>',
},
{
// These are additional custom attributes that will be added to exposure events
exampleCustomAttribute: '<attributeValue>',
},
// This should come directly from a backend or service from the Statsig.getClientInitializeResponse(user) call
initializeValues,
);
} catch (err) {
console.error('Failed to update FeatureGates user.', err);
}
如果在初始化过程中有任何问题,那么客户端将会被置于一种总是模式中 返回默认值,并返回被拒绝的许诺。 你就能抓住这个被拒的承诺 如果您希望记录自己的日志和参数,或者您希望停止申请 装入默认值.
FeatureGates 客户端只有一次实例,所以只有第一个初始化的呼叫才会开始
初始化 。 任何后续的呼唤,都会还原现有的第一个承诺
初始化, 参数值将被忽略 。 为了确认客户是否
已经开始初始化,你可以打电话 FeatureGates.initializeCalled()。 。 。 .
3. 使用提供者初始化
此初始化使用提供方的操作来获取客户端 sdk 关键值和实验值.
支助提供者有:
@atlaskit/feature-gate-single-fetch-provider@atlaskit/feature-gate-polling-provider
import FeatureGates, {
FeatureGateEnvironment,
FeatureGateProducts,
PerimeterType,
} from '@atlaskit/feature-gate-js-client';
try {
await FeatureGates.initializeWithProvider(
{
// This is an fx3 api key used to fetch the feature flag values.
// Supported keys found at go/fx3/resources/api-keys
apiKey: 'client-test',
// This is the environment that you are operating in, targeting rules can target specific environments
environment: FeatureGateEnvironment.Production,
// This will be used to filter data from Statsig to only one target app.
// View [doc](https://hello.atlassian.net/wiki/spaces/MEASURE/pages/2955970231/How-to+Use+TargetApps+in+Statsig)
// for details on using targetApp.
targetApp: 'jira_web',
// [Optional] Must be one of the strings from the exported enum PerimeterType.
// If provided, will build base url for the `feature-flag-service` based on environment and perimeter type, and
// will disable all logging to Statsig in perimeters where it is prohibited..
perimeter: PerimeterType.FEDRAMP_MODERATE,
},
new Provider(/* ... */),
{
// These are expected identifiers, you must provide them if they are relevant to your product and will be added to exposures events
analyticsAnonymousId: '<analyticsAnonymousId>',
atlassianAccountId: '<aaid>',
atlassianOrgId: '<orgid>',
tenantId: '<tenantid>',
transactionAccountId: '<transactionAccountId>',
trelloUserId: '<trelloUserId>',
trelloWorkspaceId: '<trelloWorkspaceId>',
},
{
// These are additional custom attributes that can be used for targeting and will be added to exposure events
exampleCustomAttribute: '<attributeValue>',
},
);
} catch (err) {
console.error('Failed to initialize FeatureGates client.', err);
}
如果您的应用程序有登录流程或其他机制,使用户能够
在会话中更改,然后可以使用 updateUserWithProvider 方法应用此更改.
这种方法将使用相同的提供者和选项 initializeWithProvider这需要
新用户的标识符和自定义属性。 与网络有关,它会
用于获取新的一组值.
重要性:调用这种方法将完全重新启用客户端并使用一对新的旗帜. 完成后,您需要重新发送整个页面,以确保所有东西都能接上 新旗帜值 。 您应该避免频繁使用它,因为它对用户有影响 经历.
import FeatureGates, {
FeatureGateEnvironment,
FeatureGateProducts,
} from '@atlaskit/feature-gate-js-client';
try {
await FeatureGates.updateUserWithProvider(
{
// These are expected identifiers, you must provide them if they are relevant to your product and will be added to exposures events
analyticsAnonymousId: '<analyticsAnonymousId>',
atlassianAccountId: '<aaid>',
atlassianOrgId: '<orgid>',
tenantId: '<tenantid>',
transactionAccountId: '<transactionAccountId>',
trelloUserId: '<trelloUserId>',
trelloWorkspaceId: '<trelloWorkspaceId>',
},
{
// These are additional custom attributes that can be used for targeting and will be added to exposure events
exampleCustomAttribute: '<attributeValue>',
},
);
} catch (err) {
console.error('Failed to update the FeatureGates user.', err);
}
特性旗子平台值
在从Statsig向地标旗平台迁移的过程中,旗帜由一个平台服务
或别. 与 includeFfpFlags: true, (中文(简体) ), initialize 财务报告和审定财务报表 updateUser 获取特性旗
服务 /api/v1/evalFlags 结束点, 将它们分割并返回 { statsig, ffp }因此,每个
旗帜键出现在一个平台下。 没有它,只获取 Statsig 值和 FFP
被视为残疾。 客户端读取 FFP 的密钥(通过 @atlaskit/flag-client) 当最新的FFFP
值包含它,而 Statsig 则不包含; 评估 API 不改变 :
checkGate读取 FFP 布尔旗.getExperiment编号 :getExperimentValue将 FFP JSON 对象旗读作实验参数。 任意 其他FFP旗是一面平整的 Statsig 动态配置,所以用value参数,用于 实例getExperimentValue('example.flag', 'value', 'default')。 。 。 .- 局部的覆被仍然优先,地层总是由Statsig服务.
- FFP 曝光遥测在联邦RAMP中以及何时停止使用
disableAllLogging已经设定.
从数值初始化或更新时,通过 ffp 作为服务响应的成员
可选最后一个参数 initializeFromValues 编号 : updateUserWithValues,或作为 ffp 在一个
Provider是因为 getExperimentValues 结果。 在省略后,Statsig为每一面旗帜服务. 过
不变: requestContext 需要,没有它,FFP对用户没有任何好处.
答复还有: status 每个平台: OK, (中文(简体) ), DISABLED (故意不使用)或
UNAVAILABLE (无法评价). 客户端只使用平台的值 OK, (中文(简体) ),
所以只使用不健康平台的旗帜 返回他们的代码默认值; 当没有FFP时,
该服务为仍在从Statsig迁移的旗帜服务. initialize 财务报告和审定财务报表 updateUser
获取一次。 虽然至少有一个平台 OK,或者两者都不使用,它们就会解决;当一个平台
无法使用(或既不使用),客户端登录外部生产警告并发送
degraded featureGatesClientValues 操作活动 statsigStatus, (中文(简体) ), ffpStatus 财务报告和审定财务报表
trigger 属性。 当没有平台时 OK 一个是 UNAVAILABLE (例如,Statsig为
无法使用,且 FFP 已禁用),没有值可使用,因此拒绝任何失败
获取 : initialize 仍然启动 Statsig 没有值,所以评价返回默认值,以及
updateUser 保存上一个用户的值。 供应商可以报告其价值的状况
返回通过 status 区域。 投票服务商再次打来
当平台是 UNAVAILABLE (大约30秒后,退到它的投票间隔),
但不是为了 DISABLED,并保留最后一个 OK 无法打开的平台的值
恢复状态 它用它通常的回放来重复一个没有可用平台的响应,就像5xx一样. 这个
除非用户更改,否则不重试408和429以外的4xx响应.
评价
为了评估一个大门:
import FeatureGates from '@atlaskit/feature-gate-js-client';
// Note: this checkGate call will automatically fire an exposure event
if (FeatureGates.checkGate('gateName')) {
// do something here
}
为了评估一项实验:
import FeatureGates from '@atlaskit/feature-gate-js-client';
// Note: this call will automatically fire an exposure event
if (FeatureGates.getExperimentValue('myExperiment', 'myBooleanParameter', false)) {
// do something here
}
为了使用更复杂的实验配置:
import FeatureGates from '@atlaskit/feature-gate-js-client';
// You can provide an optional function like this to reject any incoming values that don't meet your expectations.
// If this function does not pass, the default value will be returned instead.
const isHexCode = (value: unknown) =>
typeof value === 'string' && value.startsWith('#') && value.length === 7;
// Note: this call will automatically fire an exposure event. You can provide "fireExposureEvent: false" in the options if you wish to suppress it.
const buttonColor: string = FeatureGates.getExperimentValue(
'myExperiment',
'myButtonColorStringParameter',
'#000000',
{
typeGuard: isHexCode,
},
);
新建只使用FFP的旗帜与迁移的旗帜
旗帜分为两组,而产品则从Statsig移动到地物旗平台(FFP):
| 旗帜 | 读出来 | 为什么 |
|---|---|---|
| 新旗帜,只在FFP中创建 | FeatureGates.ffpClient | 它在斯达西格不存在. |
| 原已存在的Statsig旗,其中一面被迁移到FFP | checkGate, (中文(简体) ), getExperiment, (中文(简体) ), getExperimentValue | 它们从Feature Flag Service分配给它的任何平台提供每个密钥. |
读取新的只使用 FFP 的旗帜, 其输入方法为 FeatureGates.ffpClient,这是
FlagClient 联 合 国 @atlaskit/flag-client 此软件包管理 :
import FeatureGates from '@atlaskit/feature-gate-js-client';
import type { EvaluationDetails } from '@atlaskit/flag-client/types';
const enabled = FeatureGates.ffpClient?.getBooleanValue('my-new-flag', false) ?? false;
const limit = FeatureGates.ffpClient?.getNumberValue('my-new-limit', 10) ?? 10;
const theme = FeatureGates.ffpClient?.getObjectValue('my-new-theme', { color: 'blue' }) ?? {
color: 'blue',
};
// To log the exposure later, for example when the user sees the feature:
const details: EvaluationDetails<boolean> | undefined = FeatureGates.ffpClient?.getBooleanDetails(
'my-new-flag',
false,
{ disableExposureLogging: true },
);
if (details) {
FeatureGates.ffpClient?.logExposure(details);
}
ffpClient实值undefined直到一个初始化方法被调用。 之后就一样了 包括横跨updateUser打电话.- 在FFP值到达之前,当服务不为用户使用FFP时,请读回 默认你通过.
- 本地覆盖( O)
overrideGate, (中文(简体) ),overrideConfig, (中文(简体) ),setOverrides)不适用. - FFP 曝光遥测在联邦RAMP中以及何时停止使用
disableAllLogging已经设定. FfpEvaluationClient,类型ffpClient,从@atlaskit/feature-gate-js-client/ffp/types使用的方法类型(EvaluationDetails, (中文(简体) ),EvaluationOptions和其余的)来自@atlaskit/flag-client/types,所以添加@atlaskit/flag-client作为导入它们的依赖.
继续读取已有的 Statsig 旗 checkGate 或者说 getExperimentValue 当它是
迁移。 不要切换到 ffpClient数字 : ffpClient 仅服务 FFP 值,因此返回
默认任何用户 Statsig 仍然为旗帜服务 。 相反,不要只读FFP的旗帜
与 checkGate 或者说 getExperimentValue: 它们将 FFP 值映射到 Statsig 形状( 见
特性旗子平台值和正在退休
斯达西格.
方法 ffpClient 符合 FlagClient,所以一旦迁移完成,代码:
读取 ffpClient 可以移动到一个 FlagClient 从 @atlaskit/flag-client 而不改变它的读数.
曝光事件日志
曝光事件进行分批处理,并每10秒被送往Statsig. Statsig 的活动域名
looking API 被一些广告屏蔽器所屏蔽,所以默认情况下我们将通过这些请求代理
xp.atlassian.com 减少接触损失.
订阅
要订阅更改的大门。 当检查门值改变时, 调用会调用 .
import FeatureGates from '@atlaskit/feature-gate-js-client';
const unsubscribe = FeatureGates.onGateUpdated('gateName', () => {});
// To unsubscribe
unsubscribe();
要订阅对实验值的修改。 当实验值值时, 回调将被调用 变化.
import FeatureGates from '@atlaskit/feature-gate-js-client';
const unsubscribe = FeatureGates.onExperimentValueUpdated(
'myExperiment',
'myButtonColorStringParameter',
'#000000',
() => {},
{
typeGuard: isHexCode,
},
);
// To unsubscribe
unsubscribe();
订阅客户端更新的新的一组值,无论其基础是什么 价值观已经改变.
import FeatureGates from '@atlaskit/feature-gate-js-client';
// Note: The callback will be called whenever a new set of values is set even if none of the values in the set have changed.
const unsubscribe = FeatureGates.onAnyUpdated(() => {});
// To unsubscribe
unsubscribe();
基于文件的持久覆盖
对于没有浏览器本地Storage的 CLI 工具和本地开发环境,您可以使用 FilePersistentOverrideAdapter。这允许您对文件系统上的文件坚持特性标记覆盖.
不要用这个包 在丛生的背景 - 那个 FilePersistentOverrideAdapter 设计对象仅为CLI工具和当地发展环境. 它不会在浏览器环境中正常工作,并可能造成出错.
import { FilePersistentOverrideAdapter } from '@atlaskit/feature-gate-js-client/file-persistent-override-adapter';
import { FeatureGateClient } from '@atlaskit/feature-gate-js-client/client';
// Create the file override adapter with a path where overrides will be stored
const overrideAdapter = new FilePersistentOverrideAdapter('/path/to/overrides.json');
// Create a client instance with the adapter
const client = new FeatureGateClient({
overrideAdapter: overrideAdapter
});
await client.initialize({
// ... standard initialization options
});
与浏览器本地Storage适配器不同,文件适配器会创建任何存储文件的必要目录,并妥善处理文件系统错误.
单一页面上的多个客户端
通常我们不允许在单一页面上多处使用功能门客户端,因为 客户端会发出很多重的网络呼叫 可能会对运行产生巨大影响 如果许多客户在一页上存在的话。 但是,在有些情况下 将客户端隔离到产品上是绝对必要的. 我们揭发了一种方法 来抓新客户 而不是用静态方法处理此案.
由于所涉业绩问题 请在使用前询问我们 独立客户端 这样我们可以检查是否有其他的解决方案不会影响 并让我们知道需要分开客户的情况.
import FeatureGateClient from '@atlaskit/feature-gate-js-client/client';
const featureGates = new FeatureGateClient();
// Usage is the same as the static API
await featureGates.initialize({
// ...
});
featureGates.checkGate('my-gate');
孤立的云支持
客户端支持孤立的云环境,并能够 init 在IC环境中使用FFS. SDK 自动解决右边
stargate api url 基于用户提供的环境和窗口位置.
如果用户正在运行这个客户端作为服务器代码的一部分,并作为后端 SDK 并想要直接与 FFS 交谈,他们需要通过 isolationContextId 这是可选的
输入 ClientOptions。 。 。 .
SDK将根据 isolationContextId sDK将从中进行初始化.
import FeatureGates, {
FeatureGateEnvironment,
FeatureGateProducts,
PerimeterType,
} from '@atlaskit/feature-gate-js-client';
try {
await FeatureGates.initialize(
{
// This is an fx3 api key used to fetch the feature flag values.
// Supported keys found at go/fx3/resources/api-keys
apiKey: 'client-test',
isolationContextId: 'ic-7bf',
});
} catch (err) {
console.error('Failed to initialize FeatureGates client.', err);
}
测试
欢乐
测试初始化状态
您可以通过模拟返回值来测试各种初始化状态 initialize 财务报告和审定财务报表
updateUser。请注意,你还需要嘲笑 initializeCalled,因为这通常由
真实 initialize 函数.
import FeatureGates from '@atlaskit/feature-gate-js-client';
jest.mock('@atlaskit/feature-gate-js-client', () => ({
...jest.requireActual('@atlaskit/feature-gate-js-client'),
initializeCalled: jest.fn(),
initialize: jest.fn(),
updateUser: jest.fn(),
}));
const MockedFeatureGates = jest.mocked(FeatureGates);
describe('with successful initialization', () => {
beforeEach(() => {
MockedFeatureGates.initializeCalled.mockReturnValue(true);
MockedFeatureGates.initialize.mockResolvedValue();
MockedFeatureGates.updateUser.mockResolvedValue();
});
afterEach(() => jest.resetAllMocks());
});
describe('with failed initialization', () => {
beforeEach(() => {
MockedFeatureGates.initializeCalled.mockReturnValue(true);
MockedFeatureGates.initialize.mockRejectedValue();
MockedFeatureGates.updateUser.mockRejectedValue();
});
afterEach(() => jest.resetAllMocks());
});
describe('with pending initialization', () => {
// These can be called within your tests transition from the pending
// initialization state into a successful/failed state.
let resolveInitPromise;
let rejectInitPromise;
beforeEach(() => {
const initPromise = new Promise((resolve, reject) => {
resolveInitPromise = resolve;
rejectInitPromise = reject;
});
MockedFeatureGates.initializeCalled.mockReturnValue(true);
MockedFeatureGates.initialize.mockReturnValue(initPromise);
MockedFeatureGates.updateUser.mockReturnValue(initPromise);
});
afterEach(() => jest.resetAllMocks());
});
超过数值
在 Jest 测试中,可以有两种方法可以覆盖值:
- 使用模拟
- 使用内置覆盖方法
使用模拟
import FeatureGates, { DynamicConfig, EvaluationReason } from '@atlaskit/feature-gate-js-client';
jest.mock('@atlaskit/feature-gate-js-client', () => ({
...jest.requireActual('@atlaskit/feature-gate-js-client'),
getExperiment: jest.fn(),
checkGate: jest.fn(),
}));
const MockedFeatureGates = jest.mocked(FeatureGates);
describe('with mocked experiments and gates', () => {
beforeEach(() => {
const overrides = {
configs: {
'example-experiment': {
cohort: 'variation',
},
},
gates: {
'example-gate': true,
},
};
MockedFeatureGates.getExperiment.mockImplementation((experimentName) => {
const values = overrides.configs[experimentName] || {};
return new DynamicConfig(experimentName, values, 'rule-id', {
time: Date.now(),
reason: EvaluationReason.LocalOverride,
});
});
MockedFeatureGates.checkGate.mockImplementation((gateName, defaultValue) => {
return overrides.gates[gateName] || defaultValue;
});
});
afterEach(() => jest.resetAllMocks());
});
使用覆盖方法
import FeatureGates, { FeatureGateEnvironment } from '@atlaskit/feature-gate-js-client';
describe('with overridden gates and experiments', () => {
beforeAll(async () => {
// setOverrides can only be called if the client is _actually_ initialized. You can't mock the initialization, you will have invoke it properly.
await FeatureGates.initializeWithValues(
{
environment: FeatureGateEnvironment.Development,
sdkKey: 'client-default-key',
localMode: true,
},
{},
{},
);
});
beforeEach(() => {
const overrides = {
configs: {
'example-experiment': {
cohort: 'variation',
},
},
gates: {
'example-gate': true,
},
};
FeatureGates.setOverrides(overrides);
});
afterEach(() => FeatureGates.clearAllOverrides());
});
齐压
超过数值
这个 .visit 命令在 Cypress 中创建了新窗口, 并使用它自己的特异功能Gates 实例, 所以您
将无法简单地导入模块并应用分贝.
// ❌ This will not work!
import FeatureGates, { LocalOverrides } from '@atlaskit/feature-gate-js-client';
const overrides: LocalOverrides = {
configs: {
'example-experiment': {
cohort: 'variation',
},
},
gates: {
'example-gate': true,
},
};
// These interact with the FeatureGates instance that your test framework is running in
cy.stub(
FeatureGates,
'checkGate',
(gateName, defaultValue) => overrides.gates[gateName] || defaultValue,
);
cy.stub(FeatureGates, 'getExperiment', (experimentName) => {
const values = overrides.configs[experimentName] || {};
return new DynamicConfig(experimentName, values, 'rule-id', {
time: Date.now(),
reason: EvaluationReason.LocalOverride,
});
});
// This will creates a new window, with its own FeatureGates instance.
cy.visit('http://localhost:3000/');
// The test feature will not exist since the stubs don't exist on the visited window.
cy.get('#test-feature').dblclick();
相反,您需要获得存在于生成窗口上的客户端的引用,以及 应用您的功能代替.
我们暴露了一个 window.__FEATUREGATES_JS__ 变量,将包含
窗户.
// ✅ Do this instead!
import { LocalOverrides } from '@atlaskit/feature-gate-js-client';
const overrides: LocalOverrides = {
configs: {
'example-experiment': {
cohort: 'variation',
},
},
gates: {
'example-gate': true,
},
};
cy.visit('http://localhost:3001', {
// onLoad provides a reference to the generated window, and it is also only invoked when all scripts have finished loading, so the __FEATUREGATES_JS__
// variable will be available at this point.
onLoad: (contentWindow) => {
const FeatureGates = contentWindow.__FEATUREGATES_JS__;
// Note that the client would not have been initialized by this point, so we can't use the override* or setOverrides methods.
// We also don't want to wait until the initialization completes, because then the page may have already started to render without these overrides.
cy.stub(
FeatureGates,
'checkGate',
(gateName, defaultValue) => overrides.gates[gateName] || defaultValue,
);
cy.stub(FeatureGates, 'getExperiment', (experimentName) => {
const values = overrides.configs[experimentName] || {};
return new DynamicConfig(experimentName, values, {
time: Date.now(),
reason: EvaluationReason.LocalOverride,
});
});
},
});
您也可以设置您自己的自定义命令, 它会听下一个 window:load 要完成的事件
在任何页面访问前都可以引用的同样内容:
import { LocalOverrides } from '@atlaskit/feature-gate-js-client';
Cypress.Commands.add('featureGateOverrides', (overrides: LocalOverrides) => {
// Use cy.once instead of cy.on so that this only affects the next visit.
cy.once('window:load', (contentWindow) => {
const FeatureGates = contentWindow.__FEATUREGATES_JS__;
cy.stub(
FeatureGates,
'checkGate',
(gateName, defaultValue) => overrides?.gates?.[gateName] || defaultValue,
);
cy.stub(FeatureGates, 'getExperiment', (experimentName) => {
const values = overrides?.configs?.[experimentName] || {};
return new DynamicConfig(experimentName, values, {
time: Date.now(),
reason: EvaluationReason.LocalOverride,
});
});
});
});
// Once the command has been added, you can use it in any of your tests like this
cy.featureGateOverrides({
configs: {
'example-experiment': {
cohort: 'variation',
},
},
gates: {
'example-gate': true,
},
}).visit('http://localhost:3001');
剧作家
与 Cypress 类似, Playwright 要求您在页面加载后应用您的根. 我们可以利用 页面。添加Init脚本 钩入这个生命周期,以便支起 window.__FEATUREGATES_JS__。 。 。 .
超过数值
import {
LocalOverrides,
DynamicConfig,
EvaluationReason,
} from '@atlaskit/feature-gate-js-client';
import { Page } from '@playwright/test';
export async function withFeatureGateOverrides(
page: Page,
overrides: LocalOverrides,
) {
await page.addInitScript(
({ overridesSerialized, localOverrideReason }) => {
const FeatureGates = {
initialize: () => Promise.resolve(),
checkGate: (gateName: string) => {
return overridesSerialized.gates?.[gateName] ?? false;
},
getExperiment: (experimentName: string) => {
const values = overridesSerialized.configs?.[experimentName] || {};
return new DynamicConfig(experimentName, values, 'rule-id', {
time: Date.now(),
reason: localOverrideReason,
});
},
};
window.__FEATUREGATES_JS__ = {
...window.__FEATUREGATES_JS__,
...FeatureGates,
};
},
{
overridesSerialized: overrides,
localOverrideReason: EvaluationReason.LocalOverride,
},
);
}
以下是消费这个的例子:
import { expect, test } from '@playwright/test';
import { withFeatureGateOverrides } from './utils/statsig';
test.describe('Playwright test suite', () => {
test.beforeEach(async ({ page }) => {
await withFeatureGateOverrides(page, {
configs: {},
gates: {
your_feature_gate: true,
},
layers: {},
});
});
test('should pass', async ({ page }) => {
await expect(1).toEqual(1);
});
});
故事书
超过数值
故事本上没有任何嘲弄或取笑API,但你可以使用 override* 财务报告和审定财务报表
setOverrides 用于替换此客户端的方法.
请注意,在调用这些方法之前,客户必须先初始化,而且 每本故事手册被卸载后,需要清除,因为这些内容将持续 (原始内容存档于2018-10-21). localStorage.
设置最简单的方法是使用 FeatureGatesInitializationWithDefaults 构成部分
我们的反应 SDK (@atlassian/feature-gates-react与 overrides 道具集,因为这个管理
初始化和清理给你。 请看
组成部分文件 页:1
更多信息.
发展
我该怎么安排?
- 设立情况概述
- 此 repo 软件包使用纱线
- 运行
yarn install在根目录中设置您 git 钩. - 为了开始运行
yarn以安装依赖关系
- 如何运行测试
- 为了运行所有测试 只需运行
yarn test packages/measurement/feature-gate-js-client从平台目录 - 为了在运行开发时在监视模式下运行滑稽测试
yarn test:jest --watch - 注:您可能需要运行
yarn build @atlaskit/feature-gate-js-client创建版本.ts 一些测试所需的文件
- 为了运行所有测试 只需运行
捐款准则
- 所有新逻辑都必须测试
- 无需直接通过 Statsig APIs
- 参数转换算作新逻辑
- 代码审查
- 更改必须经过拉动请求才能合并
- 其他准则
释放
这个包是AFP单列波的一部分. 使用 yarn changeset 承诺.
文档
我和谁说话?
这回波是实验平台团队拥有的 伸手去 {\fn方正粗倩简体\fs12\an8\1chffff00\b0}帮助巫师 如果你需要的话 一只手。 一只手。 .