background

file location: projects\storefrontlib\src\cms-components\checkout\components\delivery-mode\delivery-mode.component.html

we are now talking about property binding of “continue” button’s disabled property.

Expected behavior

when component property deliveryModelnvalid = true, continue button’s disabled property will be set as true as well, so button is disabled, and vice versa.

Below is the getter implementation of deliveryModeInvalid in Component:

so if we set this.mode.controls[‘deliveryModeId’] to ‘’ or null, deliveryModeInvalid will equal to true.

Jerry’s observation in unit test

if we change the value of this.mode.controls[‘deliveryModeId’] TWICE in the same test spec, [disabled] and deliveryModeInvalid will LOSE synchronization, even fixture.detectChanges is called manually.

See my test below.

Paste the following source code to replace your delivery-mode.component.spec.ts and launch it:

import { Component } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ReactiveFormsModule } from '@angular/forms';
import { ActivatedRoute } from '@angular/router';
import {CheckoutDeliveryService,DeliveryMode,I18nTestingModule,
} from '@spartacus/core';
import { Observable, of } from 'rxjs';
import { CheckoutConfigService } from '../../services/checkout-config.service';
import { CheckoutStepService } from '../../services/checkout-step.service';
import { DeliveryModeComponent } from './delivery-mode.component';
import createSpy = jasmine.createSpy;
import { LoaderState } from '../../../../../../core/src/state/utils/loader';
import { By } from '@angular/platform-browser';@Component({selector: 'cx-spinner',template: '',
})
class MockSpinnerComponent {}class MockCheckoutDeliveryService {loadSupportedDeliveryModes = createSpy();setDeliveryMode = createSpy();getSupportedDeliveryModes(): Observable<DeliveryMode[]> {return of();}getSelectedDeliveryMode(): Observable<DeliveryMode> {return of();}getLoadSupportedDeliveryModeProcess(): Observable<LoaderState<void>> {return of();}
}class MockCheckoutConfigService {getPreferredDeliveryMode(): string {return '';}
}class MockCheckoutStepService {next = createSpy();back = createSpy();getBackBntText(): string {return 'common.back';}
}const mockActivatedRoute = {snapshot: {url: ['checkout', 'delivery-mode'],},
};describe('DeliveryModeComponent', () => {let component: DeliveryModeComponent;let fixture: ComponentFixture<DeliveryModeComponent>;beforeEach(async(() => {TestBed.configureTestingModule({imports: [ReactiveFormsModule, I18nTestingModule],declarations: [DeliveryModeComponent, MockSpinnerComponent],providers: [{provide: CheckoutDeliveryService,useClass: MockCheckoutDeliveryService,},{ provide: CheckoutStepService, useClass: MockCheckoutStepService },{ provide: CheckoutConfigService, useClass: MockCheckoutConfigService },{ provide: ActivatedRoute, useValue: mockActivatedRoute },],}).compileComponents();}));beforeEach(() => {fixture = TestBed.createComponent(DeliveryModeComponent);component = fixture.componentInstance;console.log('----------- a new test comes ------------------');});describe('continue button', () =>{const getContinueBtn = () => fixture.debugElement.query(By.css('.cx-checkout-btns .btn-primary'));const setDeliveryModeId = (value: string) =>  component.mode.controls['deliveryModeId'].setValue(value);function setDeliveryModeIdNull(){setDeliveryModeId(null);fixture.detectChanges();trace(null);}function setDeliveryModeIdValid(){setDeliveryModeId('a');fixture.detectChanges();trace('a');}function trace(id){const button = getContinueBtn();console.log('************** Delivery Mode id is set as: ' + id + '**************');console.log('Flag component.deliveryModeInvalid: ' + component.deliveryModeInvalid + ' button.disabled: ' + button.nativeElement.disabled );}function valid_then_null(){setDeliveryModeIdValid();setDeliveryModeIdNull();}function null_then_valid(){setDeliveryModeIdNull();setDeliveryModeIdValid();}it('first valid then null', () => {valid_then_null();expect(component).toBeTruthy();});it('null then valid', () => {null_then_valid();expect(component).toBeTruthy();});it('only valid', () => {setDeliveryModeIdValid();expect(component).toBeTruthy();});it('only null', () => {setDeliveryModeIdNull();expect(component).toBeTruthy();});});
});

In this unit test file I construct four test specs:

(1) set delivery mode id to a valid value first, then set null;
(2) set delivery mode id to null first, then set a valid value to it;
(3) only set a valid value;
(4) only set null;

In each test spec, once I manupulate the value of this.mode.controls[‘deliveryModeId’], then use console.log to display the following pair of values:

  • component.deliveryModeInvalid
  • button.nativeElement.disabled

In theory the two must always be equal.

Test result


Conclusion

Avoid change delivery mode id TWICE in a single test spec. The case to set id as A in beforeEach and set id as B in a test spec SHOULD also be considered as TWICE, so the two value will lose synchronization as well.

要获取更多Jerry的原创文章,请关注公众号"汪子熙":

工作中使用jasmine遇到的一个html element和Component绑定属性失去同步的问题相关推荐

  1. 工作中需要用到的PDF转Word技巧

    PDF格式对于工作中的人来说是一个再熟悉不过的文档格式了,每个人在日常工作中或多或少都接触过PDF文档.专业的PDF编辑软件费用高昂,那如何进行PDF编辑,已然成为一个困扰许多人的问题. 其实要进行P ...

  2. 如何在工作中保持稳定情绪?应对挑战和困扰的有效方法

    当工作中遇到压力和挑战时,保持稳定的情绪是至关重要的.稳定的情绪可以帮助我们更好地处理问题,保持专注和高效工作.在以下文章中,我将分享一些方法和技巧,帮助我们在工作中保持稳定的情绪. 自我意识和情绪管 ...

  3. 柱状图中xy轴怎么出现_如果制砂机设备在工作中出现堵料现象该怎么办?

    制砂机设备作为砂石生产线中常用的设备,在整条生产线中起着举足轻重的作用,为我国的基础建设的发展提供了巨大的贡献.但是不管技术工艺如何不断的改革完善,在制砂机设备工作中还是会出现堵料的现象.当出现这种情 ...

  4. 工作中关于rpm的一个简单但头疼的问题

    工作中关于rpm的一个简单但头疼的问题: 公司有个需要自动化更新rpm包的需求,rpm包名是:tingyun-agent-php-1.0.5-1.x86_64,本来是一个很简单的东西,一行代码就可以实 ...

  5. 工作中如何使用线程池的?自己如何定义一个线程池?

    工作中如何使用线程池的?自己如何定义一个线程池? import java.util.concurrent.*;public class MyThreadPoolDemo {public static ...

  6. 我的一个学生在运维工作中写的自动日志清理脚本程序

    本文是我的一个学生在运维工作中写的自动日志清理脚本程序,我这里不评价该shell脚本写的好与坏,只是发出来,和大家做一个分享,如果能给大家带来一点点思路上的参考就够了. 自动日志清理脚本程序 #!/b ...

  7. 记录我开发工作中遇到HTTP跨域和OPTION请求的一个坑

    我通过这篇文章把今天工作中遇到的HTTP跨域和OPTION请求的一个坑记录下来. 场景是我需要在部署在域名a的Web应用里用JavaScript去消费一个部署在域名b的服务器上的服务.域名b上的服务也 ...

  8. 实际工作中,一个完整的可视化大屏项目有哪些步骤?

    这两年数据可视化大屏成为了各家公司的网红,老板动不动开口就要"酷炫大屏",大屏的应用场景确实很多,不仅能实时监控重点数据,提高决策效率,放在公司会议室,展台等地方,还能提升公司形象 ...

  9. 工作中遇到的一个问题:

    工作中遇到的一个问题:开发的一个工具类A,因为里面要注入Dao操作数据库,但是发现这个工具类A没注入到容器中,导致里面的Dao类也没注入到A中.

最新文章

  1. 冒泡排序(java实现)
  2. MyBatis入门和全局配置文件介绍
  3. 应用交付:从技术到服务
  4. (三): 十六进制转化为rgb
  5. 有一个工程师男(女)朋友是什么样的体验?
  6. PrimeFaces在GlassFish 3.1.2.2上推动大气
  7. 破解key file时经常用到的几个API函数及其用法
  8. linux_perf_tools_full
  9. Python3 爬虫学习笔记 C17【爬虫框架 pyspider — 基本使用】
  10. 【CodeForces - 266B 】Queue at the School (模拟)
  11. htmlcss实例小项目_小程序websocket心跳库——websocket-heartbeat-miniprogram
  12. Scala的抽象语法树打印小工具-小拉达
  13. 在matlab中xt( ),编译matlab的s函数(compiling s-functions for matlab)
  14. 《孙哥说Spring5》学习笔记
  15. html5a链接_html 超链接(a)详细讲解
  16. 网易云音乐ios旧版本安装包_网易云音乐产品分析报告
  17. 网页扫雷(简易版)(一)
  18. python反编译dll_是否可以反编译.dll / .pyd文件以提取Python源代码?
  19. 短视频直播app源码——软件系统开发方案
  20. 【环境安装】Ubuntu20.04 安装yasm-1.3.0

热门文章

  1. nginx缓存服务器
  2. VMware 7.1.4安装Mac.OS.X.Lion.操作系统 key:安装 系统
  3. Centos7防火墙的常用指令
  4. bzoj2146 Construct
  5. @codeforces - 1096G@ Lucky Tickets
  6. python练习之析构函数
  7. 网络协议入门(OSI七层和TCP/IC四层协议)
  8. JS基础--函数与BOM、DOM操作、JS中的事件以及内置对象
  9. 【JZOJ3216】【SDOI2013】淘金
  10. Eclipse常用快捷键常用技巧