Popular New Releases in Mock
Faker
faker
Release v13.3.5
nock
v13.2.4
mockery
1.3.5
faker
v2.20.0
Popular Libraries in Mock
by Marak javascript
33346 NOASSERTION
generate massive amounts of realistic fake data in Node.js and the browser
by fzaninotto php
26055 NOASSERTION
Faker is a PHP library that generates fake data for you
by nuysoft javascript
17076 MIT
A simulation data generator
by joke2k python
14046 MIT
Faker is a Python package that generates fake data for you.
by nock javascript
11375 MIT
HTTP server mocking and expectations library for Node.js
by mockery php
10062 NOASSERTION
Mockery is a simple yet flexible PHP mock object framework for use in unit testing with PHPUnit, PHPSpec or any other testing framework. Its core goal is to offer a test double framework with a succinct API capable of clearly defining all possible object operations and interactions using a human readable Domain Specific Language (DSL).
by faker-ruby ruby
9969 MIT
A library for generating fake data such as names, addresses, and phone numbers.
by mswjs typescript
8934 MIT
Seamless REST/GraphQL API mocking library for browser and Node.js.
by golang go
6130 Apache-2.0
GoMock is a mocking framework for the Go programming language.
Trending New libraries in Mock
by alibaba java
1433 MIT
换种思路写Mock,让单元测试更简单
by didi go
1043 Apache-2.0
Sharingan(写轮眼)是一个基于golang的流量录制回放工具,适合项目重构、回归测试等。
by remorses typescript
411
Effortless documentation with Next.js and MDX
by LukeMathWalker rust
329 NOASSERTION
HTTP mocking to test Rust applications.
by datanymizer rust
328 MIT
Powerful database anonymizer with flexible rules. Written in Rust.
by mswjs typescript
223 MIT
Low-level HTTP/HTTPS/XHR/fetch request interception library.
by yindz java
218 Apache-2.0
简单易用的随机数据生成器。生成各种比较真实的假数据。一般用于开发和测试阶段的数据填充模拟。支持各类中国特色本地化的数据格式。An easy-to use random data generator. Generally used for data filling, simulation, demonstration and other scenarios in the development and test phase.
by D00MFist python
173 BSD-3-Clause
macOS Initial Access Payload Generator
by Huseyinnurbaki javascript
162 MIT
Free, 11MB, containerized, self-hosted mock server.
Top Authors in Mock
1
7 Libraries
133
2
5 Libraries
66
3
5 Libraries
487
4
4 Libraries
169
5
4 Libraries
1997
6
4 Libraries
12
7
4 Libraries
215
8
4 Libraries
1764
9
4 Libraries
236
10
3 Libraries
565
1
7 Libraries
133
2
5 Libraries
66
3
5 Libraries
487
4
4 Libraries
169
5
4 Libraries
1997
6
4 Libraries
12
7
4 Libraries
215
8
4 Libraries
1764
9
4 Libraries
236
10
3 Libraries
565
Trending Kits in Mock
Java Mock Open Source libraries have become an indispensable tool for developers to ensure their code is error-free. However, with so many Java Mock Open Source libraries out there, it can be difficult to discern which Java Mock Open Source libraries are the best, or if there are any that suit your project. It is always a good programming practice to write unit tests for each class we develop as part of our project. This helps us in identifying the bugs and also increases the stability of our code. Most of the time, while writing unit test cases, we need to mock external dependencies (like database connections or API calls) that we don’t want to test at that moment. We can do this with Java Mock Libraries. In this kit, we will discuss the top 8 Java Mock Open Source libraries that you can use in your testing project. mockito - popular Mocking framework for unit tests written; wiremock - A tool for mocking HTTP services; powermock - Mock |Java framework.
In software development, mock objects simulate the behavior and functionality of real objects, often to simplify unit testing. It is an object that mimics the behavior of another object, typically to simplify the testing of a class. A mock object can also be used to simulate how a client will use an API that hasn't yet been built or isn't ready for use. The procedure is a critical element of extreme programming, which relies on frequent releases in short development cycles and emphasizes comprehensive unit testing to ensure application stability. These are the 9 best Ruby Mock libraries in 2022, pact-ruby - Enables consumer-driven contract testing; Mocha - a mocking and stubbing library for Ruby; RSpec's - 'test double' framework, with support for stubbing and mocking; stripe-ruby-mock - A mocking library for testing stripe ruby.
Unit testing allows the programmer to refactor code or upgrade system libraries at a later date, and make sure the module still works correctly (e.g., in regression testing). The procedure is a critical element of extreme programming, which relies on frequent releases in short development cycles and emphasizes comprehensive unit testing to ensure application stability. Mock objects can be used as a replacement for real objects in unit testing, they often also record how they were used so that you can make assertions about this after the test has finished. Let's see the 14 best PHP Mock libraries in 2022, mockery - simple yet flexible PHP mock object framework; prophecy - Highly opinionated mocking framework for PHP 5.3; phpunit-mock-objects Mock Object library for PHPUnit.
Mock objects make it possible to write automated tests for code that depends on external services or resources. The most common scenario is when a web application depends on some kind of database. Mocking the database allows you to write tests that check that code that uses the database is operating correctly without actually performing any database operations (which may well be slow or impossible). In this kit, we will discuss the top 8 Python Mock Open Source libraries that you can use in your testing project. moto - easily mock out tests based on AWS infrastructure; responses - A utility for mocking out the Python Requests library; vcrpy - Automatically mock your HTTP interactions.
A mock object of a given class or interface is designed to simulate the behavior of the real object. Used to test the behavior of other objects that are dependent on this mock object. A mock object returns dummy data corresponding to some dummy input passed to it. Mock objects can be used as a replacement for real objects in unit testing, they often also record how they were used so that you can make assertions about this after the test has finished. In this kit, we will discuss the top 8 JavaScript Mock Open Source libraries that you can use in your testing project. nock - HTTP server mocking and expectations library for Node.js; sinon - Test spies, stubs and mocks for JavaScript; easy-mock - persistent service that generates mock data quickly.
Mocking is a process used in unit testing when the unit being tested has external dependencies. The purpose of mocking is to isolate and focus on the code being tested and not on the behavior or state of external dependencies. A mocking framework is a library that provides the ability to replace some components in your system with mock objects and make assertions about how they have been used. Go comes with built-in support for mocking: if you embed an interface in your struct, you can override it at will in your tests. Some great Go mocking libraries are testify - common assertions and mocks that plays nicely; go-sqlmock - Sql mock driver for golang to test database interactions; mockery - A mock code autogenerator for Golang.
Mocking is the act of replacing a function with a fake copy and optionally, configuring it to return some predefined data. The primary use case for mocking is unit testing. Mocking frameworks allow you to replace a specific call to a class or method with a behavior you define. Thanks to this ability, you can easily test units of code in isolation without messing up their dependencies These are the 11 best C# Mock libraries in 2022, NSubstitute - A friendly substitute for .NET mocking libraries; FakeItEasy - The easy mocking library for .NET; WireMock.Net - flexible library; pact-net - .NET version of Pact; moq.spikes - The most popular and friendly mocking framework for .NET.
Mocking frameworks allow you to replace a specific call to a class or method with a behavior you define. A mock object returns dummy data corresponding to some dummy input passed to it. Mock objects can be used as a replacement for real objects in unit testing, they often also record how they were used so that you can make assertions about this after the test has finished. When writing tests, developers often need to mock external libraries (e.g., database, network connections and etc.) to control the response from an external service. In C++, there are some good tools for this purpose.. These are the 5 best C++ Mock libraries CppUTes - unit testing and mocking framework for C/C; FakeIt - C++ mocking made easy; trompeloeil - Header only C14 mocking framework.
Trending Discussions on Mock
Change behaviour of AutoFixture with AutoMoq to return false for methods
The unauthenticated git protocol on port 9418 is no longer supported
Making a JSX syntax for a MockComponent and have it typed with typescript
Can not instantiate proxy of class: System.Net.HttpWebRequest. Could not find a parameterless constructor
Apache Beam Cloud Dataflow Streaming Stuck Side Input
How to compare file paths from JsonConfigurationSources and Directory.GetFiles properly?
How to get preview in composable functions that depend on a view model?
v0.8 AggregatorV3Interface.sol , its available in @chainlink/contracts?
Not able to mock a function inside useEffect
pytest/unittest: mock.patch function from module?
QUESTION
Change behaviour of AutoFixture with AutoMoq to return false for methods
Asked 2022-Mar-31 at 09:22Say that I have the following interface:
1public interface ITeam
2{
3 bool HasPlayer(IPlayer player);
4 void AddPlayer(IPlayer player);
5}
6
I currently have a test that looks something along the lines of (using AutoMoq):
1public interface ITeam
2{
3 bool HasPlayer(IPlayer player);
4 void AddPlayer(IPlayer player);
5}
6[Theory]
7[MyAutoData]
8public void ShouldRosterToTeamWhenPlayerIsNotRostered(Player player, Mock<ITeam> mockedTeam)
9{
10 player.RosterToTeam(mockedTeam.Object);
11
12 mockedTeam.Verify(team => team.AddPlayer(player), Times.Once);
13}
14
However, a precondition in my code is that HasPlayer
must return false for the test to pass when RosterToTeam
is called.
This can be solved by creating a ICustomization
and directly composing the correct behaviour, for example:
1public interface ITeam
2{
3 bool HasPlayer(IPlayer player);
4 void AddPlayer(IPlayer player);
5}
6[Theory]
7[MyAutoData]
8public void ShouldRosterToTeamWhenPlayerIsNotRostered(Player player, Mock<ITeam> mockedTeam)
9{
10 player.RosterToTeam(mockedTeam.Object);
11
12 mockedTeam.Verify(team => team.AddPlayer(player), Times.Once);
13}
14public class TeamCustomization : ICustomization
15{
16 public void Customize(IFixture fixture)
17 {
18 fixture.Customize<Mock<ITeam>>(composer =>
19 composer.Do(mock =>
20 mock.Setup(team => team.HasPlayer(It.IsAny<IPlayer>()))
21 .Returns(false)));
22 }
23}
24
However, I'd like my tests always to assume that the boolean methods have a default value of false. I've tried looking into ISpecimenBuilder
, but couldn't see a way to achieve this, as it seems to only work on properties, parameters, etc.
Is anyone able to recommend me a way of generically setting up all boolean methods to return false by default when created in this fashion?
Edit: The culprit behind the behaviour change is when ConfigureMembers = true
is set for AutoMoqCustomization
.
This is what my MyAutoDataAttribute
currently looks like:
1public interface ITeam
2{
3 bool HasPlayer(IPlayer player);
4 void AddPlayer(IPlayer player);
5}
6[Theory]
7[MyAutoData]
8public void ShouldRosterToTeamWhenPlayerIsNotRostered(Player player, Mock<ITeam> mockedTeam)
9{
10 player.RosterToTeam(mockedTeam.Object);
11
12 mockedTeam.Verify(team => team.AddPlayer(player), Times.Once);
13}
14public class TeamCustomization : ICustomization
15{
16 public void Customize(IFixture fixture)
17 {
18 fixture.Customize<Mock<ITeam>>(composer =>
19 composer.Do(mock =>
20 mock.Setup(team => team.HasPlayer(It.IsAny<IPlayer>()))
21 .Returns(false)));
22 }
23}
24public class MyAutoDataAttribute : AutoDataAttribute
25{
26 public MyAutoDataAttribute() : base(Create)
27 {
28 }
29
30 private static IFixture Create()
31 {
32 var fixture = new Fixture();
33
34 fixture.Customize(new AutoMoqCustomization
35 {
36 ConfigureMembers = true
37 });
38
39 fixture.Customize(new TeamCustomization());
40
41 return fixture;
42 }
43}
44
For my use case, ConfigureMembers = true
is still needed (and would like to remove the TeamCustomization
).
ANSWER
Answered 2022-Mar-26 at 16:40First of all, you may want to use AutoMoqDataAttribute to create a mock of the ITeam
interface:
1public interface ITeam
2{
3 bool HasPlayer(IPlayer player);
4 void AddPlayer(IPlayer player);
5}
6[Theory]
7[MyAutoData]
8public void ShouldRosterToTeamWhenPlayerIsNotRostered(Player player, Mock<ITeam> mockedTeam)
9{
10 player.RosterToTeam(mockedTeam.Object);
11
12 mockedTeam.Verify(team => team.AddPlayer(player), Times.Once);
13}
14public class TeamCustomization : ICustomization
15{
16 public void Customize(IFixture fixture)
17 {
18 fixture.Customize<Mock<ITeam>>(composer =>
19 composer.Do(mock =>
20 mock.Setup(team => team.HasPlayer(It.IsAny<IPlayer>()))
21 .Returns(false)));
22 }
23}
24public class MyAutoDataAttribute : AutoDataAttribute
25{
26 public MyAutoDataAttribute() : base(Create)
27 {
28 }
29
30 private static IFixture Create()
31 {
32 var fixture = new Fixture();
33
34 fixture.Customize(new AutoMoqCustomization
35 {
36 ConfigureMembers = true
37 });
38
39 fixture.Customize(new TeamCustomization());
40
41 return fixture;
42 }
43}
44public class AutoMoqDataAttribute : AutoDataAttribute
45{
46 public AutoMoqDataAttribute()
47 : base(new Fixture().Customize(new AutoMoqCustomization()))
48 {
49 }
50}
51
There is no need in cusomizing fixture to configure your mocks. You'd better do that in the tests itself (the arrange section):
1public interface ITeam
2{
3 bool HasPlayer(IPlayer player);
4 void AddPlayer(IPlayer player);
5}
6[Theory]
7[MyAutoData]
8public void ShouldRosterToTeamWhenPlayerIsNotRostered(Player player, Mock<ITeam> mockedTeam)
9{
10 player.RosterToTeam(mockedTeam.Object);
11
12 mockedTeam.Verify(team => team.AddPlayer(player), Times.Once);
13}
14public class TeamCustomization : ICustomization
15{
16 public void Customize(IFixture fixture)
17 {
18 fixture.Customize<Mock<ITeam>>(composer =>
19 composer.Do(mock =>
20 mock.Setup(team => team.HasPlayer(It.IsAny<IPlayer>()))
21 .Returns(false)));
22 }
23}
24public class MyAutoDataAttribute : AutoDataAttribute
25{
26 public MyAutoDataAttribute() : base(Create)
27 {
28 }
29
30 private static IFixture Create()
31 {
32 var fixture = new Fixture();
33
34 fixture.Customize(new AutoMoqCustomization
35 {
36 ConfigureMembers = true
37 });
38
39 fixture.Customize(new TeamCustomization());
40
41 return fixture;
42 }
43}
44public class AutoMoqDataAttribute : AutoDataAttribute
45{
46 public AutoMoqDataAttribute()
47 : base(new Fixture().Customize(new AutoMoqCustomization()))
48 {
49 }
50}
51[Theory, AutoMoqData]
52public void ShouldRosterToTeamWhenPlayerIsNotRostered(Player player, Mock<ITeam> mockedTeam)
53{
54 mockedTeam.Setup(t => t.HasPlayer(player)).Returns(false);
55 player.RosterToTeam(mockedTeam.Object);
56 mockedTeam.Verify(team => team.AddPlayer(player), Times.Once);
57}
58
59[Theory, AutoMoqData]
60public void ShouldNotRosterToTeamWhenPlayerIsRostered(Player player, Mock<ITeam> mockedTeam)
61{
62 mockedTeam.Setup(t => t.HasPlayer(player)).Returns(true);
63 player.RosterToTeam(mockedTeam.Object);
64 mockedTeam.Verify(team => team.AddPlayer(player), Times.Never);
65}
66
and, finaly, the simplified RoastToTeam implementation:
1public interface ITeam
2{
3 bool HasPlayer(IPlayer player);
4 void AddPlayer(IPlayer player);
5}
6[Theory]
7[MyAutoData]
8public void ShouldRosterToTeamWhenPlayerIsNotRostered(Player player, Mock<ITeam> mockedTeam)
9{
10 player.RosterToTeam(mockedTeam.Object);
11
12 mockedTeam.Verify(team => team.AddPlayer(player), Times.Once);
13}
14public class TeamCustomization : ICustomization
15{
16 public void Customize(IFixture fixture)
17 {
18 fixture.Customize<Mock<ITeam>>(composer =>
19 composer.Do(mock =>
20 mock.Setup(team => team.HasPlayer(It.IsAny<IPlayer>()))
21 .Returns(false)));
22 }
23}
24public class MyAutoDataAttribute : AutoDataAttribute
25{
26 public MyAutoDataAttribute() : base(Create)
27 {
28 }
29
30 private static IFixture Create()
31 {
32 var fixture = new Fixture();
33
34 fixture.Customize(new AutoMoqCustomization
35 {
36 ConfigureMembers = true
37 });
38
39 fixture.Customize(new TeamCustomization());
40
41 return fixture;
42 }
43}
44public class AutoMoqDataAttribute : AutoDataAttribute
45{
46 public AutoMoqDataAttribute()
47 : base(new Fixture().Customize(new AutoMoqCustomization()))
48 {
49 }
50}
51[Theory, AutoMoqData]
52public void ShouldRosterToTeamWhenPlayerIsNotRostered(Player player, Mock<ITeam> mockedTeam)
53{
54 mockedTeam.Setup(t => t.HasPlayer(player)).Returns(false);
55 player.RosterToTeam(mockedTeam.Object);
56 mockedTeam.Verify(team => team.AddPlayer(player), Times.Once);
57}
58
59[Theory, AutoMoqData]
60public void ShouldNotRosterToTeamWhenPlayerIsRostered(Player player, Mock<ITeam> mockedTeam)
61{
62 mockedTeam.Setup(t => t.HasPlayer(player)).Returns(true);
63 player.RosterToTeam(mockedTeam.Object);
64 mockedTeam.Verify(team => team.AddPlayer(player), Times.Never);
65}
66public class Player
67{
68 public void RosterToTeam(ITeam team)
69 {
70 if (team.HasPlayer(this))
71 {
72 return;
73 }
74 team.AddPlayer(this);
75 }
76}
77
QUESTION
The unauthenticated git protocol on port 9418 is no longer supported
Asked 2022-Mar-27 at 13:23I have been using github actions for quite sometime but today my deployments started failing. Below is the error from github action logs
1Command: git
2Arguments: ls-remote --tags --heads git://github.com/adobe-webplatform/eve.git
3Directory: /home/runner/work/stackstream-fe/stackstream-fe
4Output:
5fatal: remote error:
6 The unauthenticated git protocol on port 9418 is no longer supported.
7
Upon investigation, it appears that below section in my yml file is causing the issue.
1Command: git
2Arguments: ls-remote --tags --heads git://github.com/adobe-webplatform/eve.git
3Directory: /home/runner/work/stackstream-fe/stackstream-fe
4Output:
5fatal: remote error:
6 The unauthenticated git protocol on port 9418 is no longer supported.
7 - name: Installing modules
8 run: yarn install
9
I have looked into this change log but can't seem to comprehend the issue.
Additional Details: Server: EC2 Instance Github actions steps:
1Command: git
2Arguments: ls-remote --tags --heads git://github.com/adobe-webplatform/eve.git
3Directory: /home/runner/work/stackstream-fe/stackstream-fe
4Output:
5fatal: remote error:
6 The unauthenticated git protocol on port 9418 is no longer supported.
7 - name: Installing modules
8 run: yarn install
9 steps:
10 - name: Checkout
11 uses: actions/checkout@v2
12
13 - id: vars
14 run: |
15 if [ '${{ github.ref }}' == 'refs/heads/master' ]; then echo "::set-output name=environment::prod_stackstream" ; echo "::set-output name=api-url::api" ; elif [ '${{ github.ref }}' == 'refs/heads/staging' ]; then echo "::set-output name=environment::staging_stackstream" ; echo "::set-output name=api-url::stagingapi" ; else echo "::set-output name=environment::dev_stackstream" ; echo "::set-output name=api-url::devapi" ; fi
16
17 - uses: pCYSl5EDgo/cat@master
18 id: slack
19 with:
20 path: .github/workflows/slack.txt
21
22 - name: Slack Start Notification
23 uses: 8398a7/action-slack@v3
24 env:
25 SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
26 ENVIRONMENT: '`${{ steps.vars.outputs.environment }}`'
27 COLOR: good
28 STATUS: '`Started`'
29 with:
30 status: custom
31 fields: workflow,job,commit,repo,ref,author,took
32 custom_payload: |
33 ${{ steps.slack.outputs.text }}
34
35 - name: Installing modules
36 env:
37 REACT_APP_API_URL: 'https://${{ steps.vars.outputs.api-url }}mergestack.com/api/v1'
38 run: yarn install
39
40 - name: Create Frontend Build
41 env:
42 REACT_APP_API_URL: 'https://${{ steps.vars.outputs.api-url }}mergestack.com/api/v1'
43 run: yarn build
44
45 - name: Deploy to Frontend Server DEV
46 if: ${{ contains(github.ref, 'dev') }}
47 uses: easingthemes/ssh-deploy@v2.1.5
48 env:
49 SSH_PRIVATE_KEY: ${{ secrets.DEV_KEY }}
50 ARGS: '-rltgoDzvO --delete'
51 SOURCE: 'deploy/'
52 REMOTE_HOST: ${{ secrets.DEV_HOST }}
53 REMOTE_USER: plyfolio-dev
54 TARGET: '/home/plyfolio-dev/${{ steps.vars.outputs.environment }}/fe/deploy'
55
package.json file
1Command: git
2Arguments: ls-remote --tags --heads git://github.com/adobe-webplatform/eve.git
3Directory: /home/runner/work/stackstream-fe/stackstream-fe
4Output:
5fatal: remote error:
6 The unauthenticated git protocol on port 9418 is no longer supported.
7 - name: Installing modules
8 run: yarn install
9 steps:
10 - name: Checkout
11 uses: actions/checkout@v2
12
13 - id: vars
14 run: |
15 if [ '${{ github.ref }}' == 'refs/heads/master' ]; then echo "::set-output name=environment::prod_stackstream" ; echo "::set-output name=api-url::api" ; elif [ '${{ github.ref }}' == 'refs/heads/staging' ]; then echo "::set-output name=environment::staging_stackstream" ; echo "::set-output name=api-url::stagingapi" ; else echo "::set-output name=environment::dev_stackstream" ; echo "::set-output name=api-url::devapi" ; fi
16
17 - uses: pCYSl5EDgo/cat@master
18 id: slack
19 with:
20 path: .github/workflows/slack.txt
21
22 - name: Slack Start Notification
23 uses: 8398a7/action-slack@v3
24 env:
25 SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
26 ENVIRONMENT: '`${{ steps.vars.outputs.environment }}`'
27 COLOR: good
28 STATUS: '`Started`'
29 with:
30 status: custom
31 fields: workflow,job,commit,repo,ref,author,took
32 custom_payload: |
33 ${{ steps.slack.outputs.text }}
34
35 - name: Installing modules
36 env:
37 REACT_APP_API_URL: 'https://${{ steps.vars.outputs.api-url }}mergestack.com/api/v1'
38 run: yarn install
39
40 - name: Create Frontend Build
41 env:
42 REACT_APP_API_URL: 'https://${{ steps.vars.outputs.api-url }}mergestack.com/api/v1'
43 run: yarn build
44
45 - name: Deploy to Frontend Server DEV
46 if: ${{ contains(github.ref, 'dev') }}
47 uses: easingthemes/ssh-deploy@v2.1.5
48 env:
49 SSH_PRIVATE_KEY: ${{ secrets.DEV_KEY }}
50 ARGS: '-rltgoDzvO --delete'
51 SOURCE: 'deploy/'
52 REMOTE_HOST: ${{ secrets.DEV_HOST }}
53 REMOTE_USER: plyfolio-dev
54 TARGET: '/home/plyfolio-dev/${{ steps.vars.outputs.environment }}/fe/deploy'
55 {
56 "name": "stackstream-fe",
57 "version": "1.0.0",
58 "authors": [
59 "fayyaznofal@gmail.com"
60 ],
61 "private": true,
62 "dependencies": {
63 "@fortawesome/fontawesome-svg-core": "^1.2.34",
64 "@fortawesome/free-solid-svg-icons": "^5.15.2",
65 "@fortawesome/react-fontawesome": "^0.1.14",
66 "@fullcalendar/bootstrap": "^5.5.0",
67 "@fullcalendar/core": "^5.5.0",
68 "@fullcalendar/daygrid": "^5.5.0",
69 "@fullcalendar/interaction": "^5.5.0",
70 "@fullcalendar/react": "^5.5.0",
71 "@lourenci/react-kanban": "^2.1.0",
72 "@redux-saga/simple-saga-monitor": "^1.1.2",
73 "@testing-library/jest-dom": "^5.11.9",
74 "@testing-library/react": "^11.2.3",
75 "@testing-library/user-event": "^12.6.0",
76 "@toast-ui/react-chart": "^1.0.2",
77 "@types/jest": "^26.0.14",
78 "@types/node": "^14.10.3",
79 "@types/react": "^16.9.49",
80 "@types/react-dom": "^16.9.8",
81 "@vtaits/react-color-picker": "^0.1.1",
82 "apexcharts": "^3.23.1",
83 "availity-reactstrap-validation": "^2.7.0",
84 "axios": "^0.21.1",
85 "axios-mock-adapter": "^1.19.0",
86 "axios-progress-bar": "^1.2.0",
87 "bootstrap": "^5.0.0-beta2",
88 "chart.js": "^2.9.4",
89 "chartist": "^0.11.4",
90 "classnames": "^2.2.6",
91 "components": "^0.1.0",
92 "dotenv": "^8.2.0",
93 "draft-js": "^0.11.7",
94 "echarts": "^4.9.0",
95 "echarts-for-react": "^2.0.16",
96 "firebase": "^8.2.3",
97 "google-maps-react": "^2.0.6",
98 "history": "^4.10.1",
99 "i": "^0.3.6",
100 "i18next": "^19.8.4",
101 "i18next-browser-languagedetector": "^6.0.1",
102 "jsonwebtoken": "^8.5.1",
103 "leaflet": "^1.7.1",
104 "lodash": "^4.17.21",
105 "lodash.clonedeep": "^4.5.0",
106 "lodash.get": "^4.4.2",
107 "metismenujs": "^1.2.1",
108 "mkdirp": "^1.0.4",
109 "moment": "2.29.1",
110 "moment-timezone": "^0.5.32",
111 "nouislider-react": "^3.3.9",
112 "npm": "^7.6.3",
113 "prop-types": "^15.7.2",
114 "query-string": "^6.14.0",
115 "react": "^16.13.1",
116 "react-apexcharts": "^1.3.7",
117 "react-auth-code-input": "^1.0.0",
118 "react-avatar": "^3.10.0",
119 "react-bootstrap": "^1.5.0",
120 "react-bootstrap-editable": "^0.8.2",
121 "react-bootstrap-sweetalert": "^5.2.0",
122 "react-bootstrap-table-next": "^4.0.3",
123 "react-bootstrap-table2-editor": "^1.4.0",
124 "react-bootstrap-table2-paginator": "^2.1.2",
125 "react-bootstrap-table2-toolkit": "^2.1.3",
126 "react-chartist": "^0.14.3",
127 "react-chartjs-2": "^2.11.1",
128 "react-color": "^2.19.3",
129 "react-confirm-alert": "^2.7.0",
130 "react-content-loader": "^6.0.1",
131 "react-countdown": "^2.3.1",
132 "react-countup": "^4.3.3",
133 "react-cropper": "^2.1.4",
134 "react-data-table-component": "^6.11.8",
135 "react-date-picker": "^8.0.6",
136 "react-datepicker": "^3.4.1",
137 "react-dom": "^16.13.1",
138 "react-draft-wysiwyg": "^1.14.5",
139 "react-drag-listview": "^0.1.8",
140 "react-drawer": "^1.3.4",
141 "react-dropzone": "^11.2.4",
142 "react-dual-listbox": "^2.0.0",
143 "react-facebook-login": "^4.1.1",
144 "react-flatpickr": "^3.10.6",
145 "react-google-login": "^5.2.2",
146 "react-hook-form": "^7.15.2",
147 "react-i18next": "^11.8.5",
148 "react-icons": "^4.2.0",
149 "react-image-lightbox": "^5.1.1",
150 "react-input-mask": "^2.0.4",
151 "react-jvectormap": "^0.0.16",
152 "react-leaflet": "^3.0.5",
153 "react-meta-tags": "^1.0.1",
154 "react-modal-video": "^1.2.6",
155 "react-notifications": "^1.7.2",
156 "react-number-format": "^4.7.3",
157 "react-perfect-scrollbar": "^1.5.8",
158 "react-rangeslider": "^2.2.0",
159 "react-rating": "^2.0.5",
160 "react-rating-tooltip": "^1.1.6",
161 "react-redux": "^7.2.1",
162 "react-responsive-carousel": "^3.2.11",
163 "react-router-dom": "^5.2.0",
164 "react-script": "^2.0.5",
165 "react-scripts": "3.4.3",
166 "react-select": "^4.3.1",
167 "react-sparklines": "^1.7.0",
168 "react-star-ratings": "^2.3.0",
169 "react-super-responsive-table": "^5.2.0",
170 "react-switch": "^6.0.0",
171 "react-table": "^7.6.3",
172 "react-toastify": "^7.0.3",
173 "react-toastr": "^3.0.0",
174 "react-twitter-auth": "0.0.13",
175 "reactstrap": "^8.8.1",
176 "recharts": "^2.0.8",
177 "redux": "^4.0.5",
178 "redux-saga": "^1.1.3",
179 "reselect": "^4.0.0",
180 "sass": "^1.37.5",
181 "simplebar-react": "^2.3.0",
182 "styled": "^1.0.0",
183 "styled-components": "^5.2.1",
184 "toastr": "^2.1.4",
185 "typescript": "^4.0.2",
186 "universal-cookie": "^4.0.4"
187 },
188 "devDependencies": {
189 "@typescript-eslint/eslint-plugin": "^2.27.0",
190 "@typescript-eslint/parser": "^2.27.0",
191 "@typescript-eslint/typescript-estree": "^4.15.2",
192 "eslint-config-prettier": "^6.10.1",
193 "eslint-plugin-prettier": "^3.1.2",
194 "husky": "^4.2.5",
195 "lint-staged": "^10.1.3",
196 "prettier": "^1.19.1",
197 "react-test-renderer": "^16.13.1",
198 "redux-devtools-extension": "^2.13.8",
199 "redux-mock-store": "^1.5.4"
200 },
201 "scripts": {
202 "start": "react-scripts start",
203 "build": "react-scripts build && mv build ./deploy/build",
204 "build-local": "react-scripts build",
205 "test": "react-scripts test",
206 "eject": "react-scripts eject"
207 },
208 "eslintConfig": {
209 "extends": "react-app"
210 },
211 "husky": {
212 "hooks": {
213 "pre-commit": "lint-staged"
214 }
215 },
216 "lint-staged": {
217 "*.{js,ts,tsx}": [
218 "eslint --fix"
219 ]
220 },
221 "browserslist": {
222 "production": [
223 ">0.2%",
224 "not dead",
225 "not op_mini all"
226 ],
227 "development": [
228 "last 1 chrome version",
229 "last 1 firefox version",
230 "last 1 safari version"
231 ]
232 }
233}
234
ANSWER
Answered 2022-Mar-16 at 07:01First, this error message is indeed expected on Jan. 11th, 2022.
See "Improving Git protocol security on GitHub".
January 11, 2022 Final brownout.
This is the full brownout period where we’ll temporarily stop accepting the deprecated key and signature types, ciphers, and MACs, and the unencrypted Git protocol.
This will help clients discover any lingering use of older keys or old URLs.
Second, check your package.json
dependencies for any git://
URL, as in this example, fixed in this PR.
As noted by Jörg W Mittag:
There was a 4-month warning.
The entire Internet has been moving away from unauthenticated, unencrypted protocols for a decade, it's not like this is a huge surprise.Personally, I consider it less an "issue" and more "detecting unmaintained dependencies".
Plus, this is still only the brownout period, so the protocol will only be disabled for a short period of time, allowing developers to discover the problem.
The permanent shutdown is not until March 15th.
For GitHub Actions:
As in actions/checkout issue 14, you can add as a first step:
1Command: git
2Arguments: ls-remote --tags --heads git://github.com/adobe-webplatform/eve.git
3Directory: /home/runner/work/stackstream-fe/stackstream-fe
4Output:
5fatal: remote error:
6 The unauthenticated git protocol on port 9418 is no longer supported.
7 - name: Installing modules
8 run: yarn install
9 steps:
10 - name: Checkout
11 uses: actions/checkout@v2
12
13 - id: vars
14 run: |
15 if [ '${{ github.ref }}' == 'refs/heads/master' ]; then echo "::set-output name=environment::prod_stackstream" ; echo "::set-output name=api-url::api" ; elif [ '${{ github.ref }}' == 'refs/heads/staging' ]; then echo "::set-output name=environment::staging_stackstream" ; echo "::set-output name=api-url::stagingapi" ; else echo "::set-output name=environment::dev_stackstream" ; echo "::set-output name=api-url::devapi" ; fi
16
17 - uses: pCYSl5EDgo/cat@master
18 id: slack
19 with:
20 path: .github/workflows/slack.txt
21
22 - name: Slack Start Notification
23 uses: 8398a7/action-slack@v3
24 env:
25 SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
26 ENVIRONMENT: '`${{ steps.vars.outputs.environment }}`'
27 COLOR: good
28 STATUS: '`Started`'
29 with:
30 status: custom
31 fields: workflow,job,commit,repo,ref,author,took
32 custom_payload: |
33 ${{ steps.slack.outputs.text }}
34
35 - name: Installing modules
36 env:
37 REACT_APP_API_URL: 'https://${{ steps.vars.outputs.api-url }}mergestack.com/api/v1'
38 run: yarn install
39
40 - name: Create Frontend Build
41 env:
42 REACT_APP_API_URL: 'https://${{ steps.vars.outputs.api-url }}mergestack.com/api/v1'
43 run: yarn build
44
45 - name: Deploy to Frontend Server DEV
46 if: ${{ contains(github.ref, 'dev') }}
47 uses: easingthemes/ssh-deploy@v2.1.5
48 env:
49 SSH_PRIVATE_KEY: ${{ secrets.DEV_KEY }}
50 ARGS: '-rltgoDzvO --delete'
51 SOURCE: 'deploy/'
52 REMOTE_HOST: ${{ secrets.DEV_HOST }}
53 REMOTE_USER: plyfolio-dev
54 TARGET: '/home/plyfolio-dev/${{ steps.vars.outputs.environment }}/fe/deploy'
55 {
56 "name": "stackstream-fe",
57 "version": "1.0.0",
58 "authors": [
59 "fayyaznofal@gmail.com"
60 ],
61 "private": true,
62 "dependencies": {
63 "@fortawesome/fontawesome-svg-core": "^1.2.34",
64 "@fortawesome/free-solid-svg-icons": "^5.15.2",
65 "@fortawesome/react-fontawesome": "^0.1.14",
66 "@fullcalendar/bootstrap": "^5.5.0",
67 "@fullcalendar/core": "^5.5.0",
68 "@fullcalendar/daygrid": "^5.5.0",
69 "@fullcalendar/interaction": "^5.5.0",
70 "@fullcalendar/react": "^5.5.0",
71 "@lourenci/react-kanban": "^2.1.0",
72 "@redux-saga/simple-saga-monitor": "^1.1.2",
73 "@testing-library/jest-dom": "^5.11.9",
74 "@testing-library/react": "^11.2.3",
75 "@testing-library/user-event": "^12.6.0",
76 "@toast-ui/react-chart": "^1.0.2",
77 "@types/jest": "^26.0.14",
78 "@types/node": "^14.10.3",
79 "@types/react": "^16.9.49",
80 "@types/react-dom": "^16.9.8",
81 "@vtaits/react-color-picker": "^0.1.1",
82 "apexcharts": "^3.23.1",
83 "availity-reactstrap-validation": "^2.7.0",
84 "axios": "^0.21.1",
85 "axios-mock-adapter": "^1.19.0",
86 "axios-progress-bar": "^1.2.0",
87 "bootstrap": "^5.0.0-beta2",
88 "chart.js": "^2.9.4",
89 "chartist": "^0.11.4",
90 "classnames": "^2.2.6",
91 "components": "^0.1.0",
92 "dotenv": "^8.2.0",
93 "draft-js": "^0.11.7",
94 "echarts": "^4.9.0",
95 "echarts-for-react": "^2.0.16",
96 "firebase": "^8.2.3",
97 "google-maps-react": "^2.0.6",
98 "history": "^4.10.1",
99 "i": "^0.3.6",
100 "i18next": "^19.8.4",
101 "i18next-browser-languagedetector": "^6.0.1",
102 "jsonwebtoken": "^8.5.1",
103 "leaflet": "^1.7.1",
104 "lodash": "^4.17.21",
105 "lodash.clonedeep": "^4.5.0",
106 "lodash.get": "^4.4.2",
107 "metismenujs": "^1.2.1",
108 "mkdirp": "^1.0.4",
109 "moment": "2.29.1",
110 "moment-timezone": "^0.5.32",
111 "nouislider-react": "^3.3.9",
112 "npm": "^7.6.3",
113 "prop-types": "^15.7.2",
114 "query-string": "^6.14.0",
115 "react": "^16.13.1",
116 "react-apexcharts": "^1.3.7",
117 "react-auth-code-input": "^1.0.0",
118 "react-avatar": "^3.10.0",
119 "react-bootstrap": "^1.5.0",
120 "react-bootstrap-editable": "^0.8.2",
121 "react-bootstrap-sweetalert": "^5.2.0",
122 "react-bootstrap-table-next": "^4.0.3",
123 "react-bootstrap-table2-editor": "^1.4.0",
124 "react-bootstrap-table2-paginator": "^2.1.2",
125 "react-bootstrap-table2-toolkit": "^2.1.3",
126 "react-chartist": "^0.14.3",
127 "react-chartjs-2": "^2.11.1",
128 "react-color": "^2.19.3",
129 "react-confirm-alert": "^2.7.0",
130 "react-content-loader": "^6.0.1",
131 "react-countdown": "^2.3.1",
132 "react-countup": "^4.3.3",
133 "react-cropper": "^2.1.4",
134 "react-data-table-component": "^6.11.8",
135 "react-date-picker": "^8.0.6",
136 "react-datepicker": "^3.4.1",
137 "react-dom": "^16.13.1",
138 "react-draft-wysiwyg": "^1.14.5",
139 "react-drag-listview": "^0.1.8",
140 "react-drawer": "^1.3.4",
141 "react-dropzone": "^11.2.4",
142 "react-dual-listbox": "^2.0.0",
143 "react-facebook-login": "^4.1.1",
144 "react-flatpickr": "^3.10.6",
145 "react-google-login": "^5.2.2",
146 "react-hook-form": "^7.15.2",
147 "react-i18next": "^11.8.5",
148 "react-icons": "^4.2.0",
149 "react-image-lightbox": "^5.1.1",
150 "react-input-mask": "^2.0.4",
151 "react-jvectormap": "^0.0.16",
152 "react-leaflet": "^3.0.5",
153 "react-meta-tags": "^1.0.1",
154 "react-modal-video": "^1.2.6",
155 "react-notifications": "^1.7.2",
156 "react-number-format": "^4.7.3",
157 "react-perfect-scrollbar": "^1.5.8",
158 "react-rangeslider": "^2.2.0",
159 "react-rating": "^2.0.5",
160 "react-rating-tooltip": "^1.1.6",
161 "react-redux": "^7.2.1",
162 "react-responsive-carousel": "^3.2.11",
163 "react-router-dom": "^5.2.0",
164 "react-script": "^2.0.5",
165 "react-scripts": "3.4.3",
166 "react-select": "^4.3.1",
167 "react-sparklines": "^1.7.0",
168 "react-star-ratings": "^2.3.0",
169 "react-super-responsive-table": "^5.2.0",
170 "react-switch": "^6.0.0",
171 "react-table": "^7.6.3",
172 "react-toastify": "^7.0.3",
173 "react-toastr": "^3.0.0",
174 "react-twitter-auth": "0.0.13",
175 "reactstrap": "^8.8.1",
176 "recharts": "^2.0.8",
177 "redux": "^4.0.5",
178 "redux-saga": "^1.1.3",
179 "reselect": "^4.0.0",
180 "sass": "^1.37.5",
181 "simplebar-react": "^2.3.0",
182 "styled": "^1.0.0",
183 "styled-components": "^5.2.1",
184 "toastr": "^2.1.4",
185 "typescript": "^4.0.2",
186 "universal-cookie": "^4.0.4"
187 },
188 "devDependencies": {
189 "@typescript-eslint/eslint-plugin": "^2.27.0",
190 "@typescript-eslint/parser": "^2.27.0",
191 "@typescript-eslint/typescript-estree": "^4.15.2",
192 "eslint-config-prettier": "^6.10.1",
193 "eslint-plugin-prettier": "^3.1.2",
194 "husky": "^4.2.5",
195 "lint-staged": "^10.1.3",
196 "prettier": "^1.19.1",
197 "react-test-renderer": "^16.13.1",
198 "redux-devtools-extension": "^2.13.8",
199 "redux-mock-store": "^1.5.4"
200 },
201 "scripts": {
202 "start": "react-scripts start",
203 "build": "react-scripts build && mv build ./deploy/build",
204 "build-local": "react-scripts build",
205 "test": "react-scripts test",
206 "eject": "react-scripts eject"
207 },
208 "eslintConfig": {
209 "extends": "react-app"
210 },
211 "husky": {
212 "hooks": {
213 "pre-commit": "lint-staged"
214 }
215 },
216 "lint-staged": {
217 "*.{js,ts,tsx}": [
218 "eslint --fix"
219 ]
220 },
221 "browserslist": {
222 "production": [
223 ">0.2%",
224 "not dead",
225 "not op_mini all"
226 ],
227 "development": [
228 "last 1 chrome version",
229 "last 1 firefox version",
230 "last 1 safari version"
231 ]
232 }
233}
234 - name: Fix up git URLs
235 run: echo -e '[url "https://github.com/"]\n insteadOf = "git://github.com/"' >> ~/.gitconfig
236
That will change any git://github.com/
into https://github.com/
.
For all your repositories, you can set:
1Command: git
2Arguments: ls-remote --tags --heads git://github.com/adobe-webplatform/eve.git
3Directory: /home/runner/work/stackstream-fe/stackstream-fe
4Output:
5fatal: remote error:
6 The unauthenticated git protocol on port 9418 is no longer supported.
7 - name: Installing modules
8 run: yarn install
9 steps:
10 - name: Checkout
11 uses: actions/checkout@v2
12
13 - id: vars
14 run: |
15 if [ '${{ github.ref }}' == 'refs/heads/master' ]; then echo "::set-output name=environment::prod_stackstream" ; echo "::set-output name=api-url::api" ; elif [ '${{ github.ref }}' == 'refs/heads/staging' ]; then echo "::set-output name=environment::staging_stackstream" ; echo "::set-output name=api-url::stagingapi" ; else echo "::set-output name=environment::dev_stackstream" ; echo "::set-output name=api-url::devapi" ; fi
16
17 - uses: pCYSl5EDgo/cat@master
18 id: slack
19 with:
20 path: .github/workflows/slack.txt
21
22 - name: Slack Start Notification
23 uses: 8398a7/action-slack@v3
24 env:
25 SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
26 ENVIRONMENT: '`${{ steps.vars.outputs.environment }}`'
27 COLOR: good
28 STATUS: '`Started`'
29 with:
30 status: custom
31 fields: workflow,job,commit,repo,ref,author,took
32 custom_payload: |
33 ${{ steps.slack.outputs.text }}
34
35 - name: Installing modules
36 env:
37 REACT_APP_API_URL: 'https://${{ steps.vars.outputs.api-url }}mergestack.com/api/v1'
38 run: yarn install
39
40 - name: Create Frontend Build
41 env:
42 REACT_APP_API_URL: 'https://${{ steps.vars.outputs.api-url }}mergestack.com/api/v1'
43 run: yarn build
44
45 - name: Deploy to Frontend Server DEV
46 if: ${{ contains(github.ref, 'dev') }}
47 uses: easingthemes/ssh-deploy@v2.1.5
48 env:
49 SSH_PRIVATE_KEY: ${{ secrets.DEV_KEY }}
50 ARGS: '-rltgoDzvO --delete'
51 SOURCE: 'deploy/'
52 REMOTE_HOST: ${{ secrets.DEV_HOST }}
53 REMOTE_USER: plyfolio-dev
54 TARGET: '/home/plyfolio-dev/${{ steps.vars.outputs.environment }}/fe/deploy'
55 {
56 "name": "stackstream-fe",
57 "version": "1.0.0",
58 "authors": [
59 "fayyaznofal@gmail.com"
60 ],
61 "private": true,
62 "dependencies": {
63 "@fortawesome/fontawesome-svg-core": "^1.2.34",
64 "@fortawesome/free-solid-svg-icons": "^5.15.2",
65 "@fortawesome/react-fontawesome": "^0.1.14",
66 "@fullcalendar/bootstrap": "^5.5.0",
67 "@fullcalendar/core": "^5.5.0",
68 "@fullcalendar/daygrid": "^5.5.0",
69 "@fullcalendar/interaction": "^5.5.0",
70 "@fullcalendar/react": "^5.5.0",
71 "@lourenci/react-kanban": "^2.1.0",
72 "@redux-saga/simple-saga-monitor": "^1.1.2",
73 "@testing-library/jest-dom": "^5.11.9",
74 "@testing-library/react": "^11.2.3",
75 "@testing-library/user-event": "^12.6.0",
76 "@toast-ui/react-chart": "^1.0.2",
77 "@types/jest": "^26.0.14",
78 "@types/node": "^14.10.3",
79 "@types/react": "^16.9.49",
80 "@types/react-dom": "^16.9.8",
81 "@vtaits/react-color-picker": "^0.1.1",
82 "apexcharts": "^3.23.1",
83 "availity-reactstrap-validation": "^2.7.0",
84 "axios": "^0.21.1",
85 "axios-mock-adapter": "^1.19.0",
86 "axios-progress-bar": "^1.2.0",
87 "bootstrap": "^5.0.0-beta2",
88 "chart.js": "^2.9.4",
89 "chartist": "^0.11.4",
90 "classnames": "^2.2.6",
91 "components": "^0.1.0",
92 "dotenv": "^8.2.0",
93 "draft-js": "^0.11.7",
94 "echarts": "^4.9.0",
95 "echarts-for-react": "^2.0.16",
96 "firebase": "^8.2.3",
97 "google-maps-react": "^2.0.6",
98 "history": "^4.10.1",
99 "i": "^0.3.6",
100 "i18next": "^19.8.4",
101 "i18next-browser-languagedetector": "^6.0.1",
102 "jsonwebtoken": "^8.5.1",
103 "leaflet": "^1.7.1",
104 "lodash": "^4.17.21",
105 "lodash.clonedeep": "^4.5.0",
106 "lodash.get": "^4.4.2",
107 "metismenujs": "^1.2.1",
108 "mkdirp": "^1.0.4",
109 "moment": "2.29.1",
110 "moment-timezone": "^0.5.32",
111 "nouislider-react": "^3.3.9",
112 "npm": "^7.6.3",
113 "prop-types": "^15.7.2",
114 "query-string": "^6.14.0",
115 "react": "^16.13.1",
116 "react-apexcharts": "^1.3.7",
117 "react-auth-code-input": "^1.0.0",
118 "react-avatar": "^3.10.0",
119 "react-bootstrap": "^1.5.0",
120 "react-bootstrap-editable": "^0.8.2",
121 "react-bootstrap-sweetalert": "^5.2.0",
122 "react-bootstrap-table-next": "^4.0.3",
123 "react-bootstrap-table2-editor": "^1.4.0",
124 "react-bootstrap-table2-paginator": "^2.1.2",
125 "react-bootstrap-table2-toolkit": "^2.1.3",
126 "react-chartist": "^0.14.3",
127 "react-chartjs-2": "^2.11.1",
128 "react-color": "^2.19.3",
129 "react-confirm-alert": "^2.7.0",
130 "react-content-loader": "^6.0.1",
131 "react-countdown": "^2.3.1",
132 "react-countup": "^4.3.3",
133 "react-cropper": "^2.1.4",
134 "react-data-table-component": "^6.11.8",
135 "react-date-picker": "^8.0.6",
136 "react-datepicker": "^3.4.1",
137 "react-dom": "^16.13.1",
138 "react-draft-wysiwyg": "^1.14.5",
139 "react-drag-listview": "^0.1.8",
140 "react-drawer": "^1.3.4",
141 "react-dropzone": "^11.2.4",
142 "react-dual-listbox": "^2.0.0",
143 "react-facebook-login": "^4.1.1",
144 "react-flatpickr": "^3.10.6",
145 "react-google-login": "^5.2.2",
146 "react-hook-form": "^7.15.2",
147 "react-i18next": "^11.8.5",
148 "react-icons": "^4.2.0",
149 "react-image-lightbox": "^5.1.1",
150 "react-input-mask": "^2.0.4",
151 "react-jvectormap": "^0.0.16",
152 "react-leaflet": "^3.0.5",
153 "react-meta-tags": "^1.0.1",
154 "react-modal-video": "^1.2.6",
155 "react-notifications": "^1.7.2",
156 "react-number-format": "^4.7.3",
157 "react-perfect-scrollbar": "^1.5.8",
158 "react-rangeslider": "^2.2.0",
159 "react-rating": "^2.0.5",
160 "react-rating-tooltip": "^1.1.6",
161 "react-redux": "^7.2.1",
162 "react-responsive-carousel": "^3.2.11",
163 "react-router-dom": "^5.2.0",
164 "react-script": "^2.0.5",
165 "react-scripts": "3.4.3",
166 "react-select": "^4.3.1",
167 "react-sparklines": "^1.7.0",
168 "react-star-ratings": "^2.3.0",
169 "react-super-responsive-table": "^5.2.0",
170 "react-switch": "^6.0.0",
171 "react-table": "^7.6.3",
172 "react-toastify": "^7.0.3",
173 "react-toastr": "^3.0.0",
174 "react-twitter-auth": "0.0.13",
175 "reactstrap": "^8.8.1",
176 "recharts": "^2.0.8",
177 "redux": "^4.0.5",
178 "redux-saga": "^1.1.3",
179 "reselect": "^4.0.0",
180 "sass": "^1.37.5",
181 "simplebar-react": "^2.3.0",
182 "styled": "^1.0.0",
183 "styled-components": "^5.2.1",
184 "toastr": "^2.1.4",
185 "typescript": "^4.0.2",
186 "universal-cookie": "^4.0.4"
187 },
188 "devDependencies": {
189 "@typescript-eslint/eslint-plugin": "^2.27.0",
190 "@typescript-eslint/parser": "^2.27.0",
191 "@typescript-eslint/typescript-estree": "^4.15.2",
192 "eslint-config-prettier": "^6.10.1",
193 "eslint-plugin-prettier": "^3.1.2",
194 "husky": "^4.2.5",
195 "lint-staged": "^10.1.3",
196 "prettier": "^1.19.1",
197 "react-test-renderer": "^16.13.1",
198 "redux-devtools-extension": "^2.13.8",
199 "redux-mock-store": "^1.5.4"
200 },
201 "scripts": {
202 "start": "react-scripts start",
203 "build": "react-scripts build && mv build ./deploy/build",
204 "build-local": "react-scripts build",
205 "test": "react-scripts test",
206 "eject": "react-scripts eject"
207 },
208 "eslintConfig": {
209 "extends": "react-app"
210 },
211 "husky": {
212 "hooks": {
213 "pre-commit": "lint-staged"
214 }
215 },
216 "lint-staged": {
217 "*.{js,ts,tsx}": [
218 "eslint --fix"
219 ]
220 },
221 "browserslist": {
222 "production": [
223 ">0.2%",
224 "not dead",
225 "not op_mini all"
226 ],
227 "development": [
228 "last 1 chrome version",
229 "last 1 firefox version",
230 "last 1 safari version"
231 ]
232 }
233}
234 - name: Fix up git URLs
235 run: echo -e '[url "https://github.com/"]\n insteadOf = "git://github.com/"' >> ~/.gitconfig
236git config --global url."https://github.com/".insteadOf git://github.com/
237
You can also use SSH, but GitHub Security reminds us that, as of March 15th, 2022, GitHub stopped accepting DSA keys. RSA keys uploaded after Nov 2, 2021 will work only with SHA-2 signatures.
The deprecated MACs, ciphers, and unencrypted Git protocol are permanently disabled.
So this (with the right key) would work:
1Command: git
2Arguments: ls-remote --tags --heads git://github.com/adobe-webplatform/eve.git
3Directory: /home/runner/work/stackstream-fe/stackstream-fe
4Output:
5fatal: remote error:
6 The unauthenticated git protocol on port 9418 is no longer supported.
7 - name: Installing modules
8 run: yarn install
9 steps:
10 - name: Checkout
11 uses: actions/checkout@v2
12
13 - id: vars
14 run: |
15 if [ '${{ github.ref }}' == 'refs/heads/master' ]; then echo "::set-output name=environment::prod_stackstream" ; echo "::set-output name=api-url::api" ; elif [ '${{ github.ref }}' == 'refs/heads/staging' ]; then echo "::set-output name=environment::staging_stackstream" ; echo "::set-output name=api-url::stagingapi" ; else echo "::set-output name=environment::dev_stackstream" ; echo "::set-output name=api-url::devapi" ; fi
16
17 - uses: pCYSl5EDgo/cat@master
18 id: slack
19 with:
20 path: .github/workflows/slack.txt
21
22 - name: Slack Start Notification
23 uses: 8398a7/action-slack@v3
24 env:
25 SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
26 ENVIRONMENT: '`${{ steps.vars.outputs.environment }}`'
27 COLOR: good
28 STATUS: '`Started`'
29 with:
30 status: custom
31 fields: workflow,job,commit,repo,ref,author,took
32 custom_payload: |
33 ${{ steps.slack.outputs.text }}
34
35 - name: Installing modules
36 env:
37 REACT_APP_API_URL: 'https://${{ steps.vars.outputs.api-url }}mergestack.com/api/v1'
38 run: yarn install
39
40 - name: Create Frontend Build
41 env:
42 REACT_APP_API_URL: 'https://${{ steps.vars.outputs.api-url }}mergestack.com/api/v1'
43 run: yarn build
44
45 - name: Deploy to Frontend Server DEV
46 if: ${{ contains(github.ref, 'dev') }}
47 uses: easingthemes/ssh-deploy@v2.1.5
48 env:
49 SSH_PRIVATE_KEY: ${{ secrets.DEV_KEY }}
50 ARGS: '-rltgoDzvO --delete'
51 SOURCE: 'deploy/'
52 REMOTE_HOST: ${{ secrets.DEV_HOST }}
53 REMOTE_USER: plyfolio-dev
54 TARGET: '/home/plyfolio-dev/${{ steps.vars.outputs.environment }}/fe/deploy'
55 {
56 "name": "stackstream-fe",
57 "version": "1.0.0",
58 "authors": [
59 "fayyaznofal@gmail.com"
60 ],
61 "private": true,
62 "dependencies": {
63 "@fortawesome/fontawesome-svg-core": "^1.2.34",
64 "@fortawesome/free-solid-svg-icons": "^5.15.2",
65 "@fortawesome/react-fontawesome": "^0.1.14",
66 "@fullcalendar/bootstrap": "^5.5.0",
67 "@fullcalendar/core": "^5.5.0",
68 "@fullcalendar/daygrid": "^5.5.0",
69 "@fullcalendar/interaction": "^5.5.0",
70 "@fullcalendar/react": "^5.5.0",
71 "@lourenci/react-kanban": "^2.1.0",
72 "@redux-saga/simple-saga-monitor": "^1.1.2",
73 "@testing-library/jest-dom": "^5.11.9",
74 "@testing-library/react": "^11.2.3",
75 "@testing-library/user-event": "^12.6.0",
76 "@toast-ui/react-chart": "^1.0.2",
77 "@types/jest": "^26.0.14",
78 "@types/node": "^14.10.3",
79 "@types/react": "^16.9.49",
80 "@types/react-dom": "^16.9.8",
81 "@vtaits/react-color-picker": "^0.1.1",
82 "apexcharts": "^3.23.1",
83 "availity-reactstrap-validation": "^2.7.0",
84 "axios": "^0.21.1",
85 "axios-mock-adapter": "^1.19.0",
86 "axios-progress-bar": "^1.2.0",
87 "bootstrap": "^5.0.0-beta2",
88 "chart.js": "^2.9.4",
89 "chartist": "^0.11.4",
90 "classnames": "^2.2.6",
91 "components": "^0.1.0",
92 "dotenv": "^8.2.0",
93 "draft-js": "^0.11.7",
94 "echarts": "^4.9.0",
95 "echarts-for-react": "^2.0.16",
96 "firebase": "^8.2.3",
97 "google-maps-react": "^2.0.6",
98 "history": "^4.10.1",
99 "i": "^0.3.6",
100 "i18next": "^19.8.4",
101 "i18next-browser-languagedetector": "^6.0.1",
102 "jsonwebtoken": "^8.5.1",
103 "leaflet": "^1.7.1",
104 "lodash": "^4.17.21",
105 "lodash.clonedeep": "^4.5.0",
106 "lodash.get": "^4.4.2",
107 "metismenujs": "^1.2.1",
108 "mkdirp": "^1.0.4",
109 "moment": "2.29.1",
110 "moment-timezone": "^0.5.32",
111 "nouislider-react": "^3.3.9",
112 "npm": "^7.6.3",
113 "prop-types": "^15.7.2",
114 "query-string": "^6.14.0",
115 "react": "^16.13.1",
116 "react-apexcharts": "^1.3.7",
117 "react-auth-code-input": "^1.0.0",
118 "react-avatar": "^3.10.0",
119 "react-bootstrap": "^1.5.0",
120 "react-bootstrap-editable": "^0.8.2",
121 "react-bootstrap-sweetalert": "^5.2.0",
122 "react-bootstrap-table-next": "^4.0.3",
123 "react-bootstrap-table2-editor": "^1.4.0",
124 "react-bootstrap-table2-paginator": "^2.1.2",
125 "react-bootstrap-table2-toolkit": "^2.1.3",
126 "react-chartist": "^0.14.3",
127 "react-chartjs-2": "^2.11.1",
128 "react-color": "^2.19.3",
129 "react-confirm-alert": "^2.7.0",
130 "react-content-loader": "^6.0.1",
131 "react-countdown": "^2.3.1",
132 "react-countup": "^4.3.3",
133 "react-cropper": "^2.1.4",
134 "react-data-table-component": "^6.11.8",
135 "react-date-picker": "^8.0.6",
136 "react-datepicker": "^3.4.1",
137 "react-dom": "^16.13.1",
138 "react-draft-wysiwyg": "^1.14.5",
139 "react-drag-listview": "^0.1.8",
140 "react-drawer": "^1.3.4",
141 "react-dropzone": "^11.2.4",
142 "react-dual-listbox": "^2.0.0",
143 "react-facebook-login": "^4.1.1",
144 "react-flatpickr": "^3.10.6",
145 "react-google-login": "^5.2.2",
146 "react-hook-form": "^7.15.2",
147 "react-i18next": "^11.8.5",
148 "react-icons": "^4.2.0",
149 "react-image-lightbox": "^5.1.1",
150 "react-input-mask": "^2.0.4",
151 "react-jvectormap": "^0.0.16",
152 "react-leaflet": "^3.0.5",
153 "react-meta-tags": "^1.0.1",
154 "react-modal-video": "^1.2.6",
155 "react-notifications": "^1.7.2",
156 "react-number-format": "^4.7.3",
157 "react-perfect-scrollbar": "^1.5.8",
158 "react-rangeslider": "^2.2.0",
159 "react-rating": "^2.0.5",
160 "react-rating-tooltip": "^1.1.6",
161 "react-redux": "^7.2.1",
162 "react-responsive-carousel": "^3.2.11",
163 "react-router-dom": "^5.2.0",
164 "react-script": "^2.0.5",
165 "react-scripts": "3.4.3",
166 "react-select": "^4.3.1",
167 "react-sparklines": "^1.7.0",
168 "react-star-ratings": "^2.3.0",
169 "react-super-responsive-table": "^5.2.0",
170 "react-switch": "^6.0.0",
171 "react-table": "^7.6.3",
172 "react-toastify": "^7.0.3",
173 "react-toastr": "^3.0.0",
174 "react-twitter-auth": "0.0.13",
175 "reactstrap": "^8.8.1",
176 "recharts": "^2.0.8",
177 "redux": "^4.0.5",
178 "redux-saga": "^1.1.3",
179 "reselect": "^4.0.0",
180 "sass": "^1.37.5",
181 "simplebar-react": "^2.3.0",
182 "styled": "^1.0.0",
183 "styled-components": "^5.2.1",
184 "toastr": "^2.1.4",
185 "typescript": "^4.0.2",
186 "universal-cookie": "^4.0.4"
187 },
188 "devDependencies": {
189 "@typescript-eslint/eslint-plugin": "^2.27.0",
190 "@typescript-eslint/parser": "^2.27.0",
191 "@typescript-eslint/typescript-estree": "^4.15.2",
192 "eslint-config-prettier": "^6.10.1",
193 "eslint-plugin-prettier": "^3.1.2",
194 "husky": "^4.2.5",
195 "lint-staged": "^10.1.3",
196 "prettier": "^1.19.1",
197 "react-test-renderer": "^16.13.1",
198 "redux-devtools-extension": "^2.13.8",
199 "redux-mock-store": "^1.5.4"
200 },
201 "scripts": {
202 "start": "react-scripts start",
203 "build": "react-scripts build && mv build ./deploy/build",
204 "build-local": "react-scripts build",
205 "test": "react-scripts test",
206 "eject": "react-scripts eject"
207 },
208 "eslintConfig": {
209 "extends": "react-app"
210 },
211 "husky": {
212 "hooks": {
213 "pre-commit": "lint-staged"
214 }
215 },
216 "lint-staged": {
217 "*.{js,ts,tsx}": [
218 "eslint --fix"
219 ]
220 },
221 "browserslist": {
222 "production": [
223 ">0.2%",
224 "not dead",
225 "not op_mini all"
226 ],
227 "development": [
228 "last 1 chrome version",
229 "last 1 firefox version",
230 "last 1 safari version"
231 ]
232 }
233}
234 - name: Fix up git URLs
235 run: echo -e '[url "https://github.com/"]\n insteadOf = "git://github.com/"' >> ~/.gitconfig
236git config --global url."https://github.com/".insteadOf git://github.com/
237git config --global url."git@github.com:".insteadOf git://github.com/
238
That will change any git://github.com/
(unencrypted Git protocol) into git@github.com:
(SSH URL).
QUESTION
Making a JSX syntax for a MockComponent and have it typed with typescript
Asked 2022-Mar-20 at 22:37Wondering if anybody has some good suggestions on how to crack this. Got this test helper utils I have added some types to:
1import { jest } from '@jest/globals'
2import React from 'react'
3
4// https://learn.reactnativeschool.com/courses/781007/lectures/14173979
5export function mockComponent(moduleName: string, propOverrideFn = (props: Record<string, any>) => ({})) {
6 const RealComponent = jest.requireActual(moduleName) as React.ComponentType<any>
7 const CustomizedComponent = (props: Record<string, any>) => {
8 return React.createElement(
9 'CustomizedComponent',
10 {
11 ...props,
12 ...propOverrideFn(props),
13 },
14 props.children
15 )
16 }
17 CustomizedComponent.propTypes = RealComponent.propTypes
18
19 return CustomizedComponent
20}
21
So currently I can call it like this
1import { jest } from '@jest/globals'
2import React from 'react'
3
4// https://learn.reactnativeschool.com/courses/781007/lectures/14173979
5export function mockComponent(moduleName: string, propOverrideFn = (props: Record<string, any>) => ({})) {
6 const RealComponent = jest.requireActual(moduleName) as React.ComponentType<any>
7 const CustomizedComponent = (props: Record<string, any>) => {
8 return React.createElement(
9 'CustomizedComponent',
10 {
11 ...props,
12 ...propOverrideFn(props),
13 },
14 props.children
15 )
16 }
17 CustomizedComponent.propTypes = RealComponent.propTypes
18
19 return CustomizedComponent
20}
21jest.mock('react-native/Libraries/Components/Touchable/TouchableOpacity', () => {
22 return mockComponent('react-native/Libraries/Components/Touchable/TouchableOpacity', (props) => {
23 return {
24 onPress: props.disabled ? () => {} : props.onPress
25 }
26 })
27})
28
But I would like to be able to call it more like
1import { jest } from '@jest/globals'
2import React from 'react'
3
4// https://learn.reactnativeschool.com/courses/781007/lectures/14173979
5export function mockComponent(moduleName: string, propOverrideFn = (props: Record<string, any>) => ({})) {
6 const RealComponent = jest.requireActual(moduleName) as React.ComponentType<any>
7 const CustomizedComponent = (props: Record<string, any>) => {
8 return React.createElement(
9 'CustomizedComponent',
10 {
11 ...props,
12 ...propOverrideFn(props),
13 },
14 props.children
15 )
16 }
17 CustomizedComponent.propTypes = RealComponent.propTypes
18
19 return CustomizedComponent
20}
21jest.mock('react-native/Libraries/Components/Touchable/TouchableOpacity', () => {
22 return mockComponent('react-native/Libraries/Components/Touchable/TouchableOpacity', (props) => {
23 return {
24 onPress: props.disabled ? () => {} : props.onPress
25 }
26 })
27})
28
29jest.mock('react-native/Libraries/Components/Touchable/TouchableOpacity', () => {
30 return <MockComponent
31 module='TouchableOpacity'
32 onPress={props => props.disabled ? () => {} : props.onPress}
33 />
34})
35
36
or
1import { jest } from '@jest/globals'
2import React from 'react'
3
4// https://learn.reactnativeschool.com/courses/781007/lectures/14173979
5export function mockComponent(moduleName: string, propOverrideFn = (props: Record<string, any>) => ({})) {
6 const RealComponent = jest.requireActual(moduleName) as React.ComponentType<any>
7 const CustomizedComponent = (props: Record<string, any>) => {
8 return React.createElement(
9 'CustomizedComponent',
10 {
11 ...props,
12 ...propOverrideFn(props),
13 },
14 props.children
15 )
16 }
17 CustomizedComponent.propTypes = RealComponent.propTypes
18
19 return CustomizedComponent
20}
21jest.mock('react-native/Libraries/Components/Touchable/TouchableOpacity', () => {
22 return mockComponent('react-native/Libraries/Components/Touchable/TouchableOpacity', (props) => {
23 return {
24 onPress: props.disabled ? () => {} : props.onPress
25 }
26 })
27})
28
29jest.mock('react-native/Libraries/Components/Touchable/TouchableOpacity', () => {
30 return <MockComponent
31 module='TouchableOpacity'
32 onPress={props => props.disabled ? () => {} : props.onPress}
33 />
34})
35
36jest.mock('react-native/Libraries/Components/Touchable/TouchableOpacity', () => {
37 return <MockComponent
38 module='TouchableOpacity'
39 propOverride={props => ({onPress: props.disabled ? () => {} : props.onPress, ...props})}
40 />
41})
42
ANSWER
Answered 2022-Mar-20 at 22:37If you look at React without JSX, you'll see that the XML-inspired syntax (<MockComponent />
) is just short for React.createElement('MockComponent')
.
Right now, if you renamed mockComponent
to MockComponent
and tried using the angle bracket syntax, the first issue is that your function receives two arguments. React components are either class components that take one constructor argument (props) or functional components that take one argument (again, props). The second issue is that your function returns a React functional component, when it needs to return a rendered React element.
One way to fix this issue is to convert mockComponent
into a React functional component and make module
and propOverride
props of the FC.
1import { jest } from '@jest/globals'
2import React from 'react'
3
4// https://learn.reactnativeschool.com/courses/781007/lectures/14173979
5export function mockComponent(moduleName: string, propOverrideFn = (props: Record<string, any>) => ({})) {
6 const RealComponent = jest.requireActual(moduleName) as React.ComponentType<any>
7 const CustomizedComponent = (props: Record<string, any>) => {
8 return React.createElement(
9 'CustomizedComponent',
10 {
11 ...props,
12 ...propOverrideFn(props),
13 },
14 props.children
15 )
16 }
17 CustomizedComponent.propTypes = RealComponent.propTypes
18
19 return CustomizedComponent
20}
21jest.mock('react-native/Libraries/Components/Touchable/TouchableOpacity', () => {
22 return mockComponent('react-native/Libraries/Components/Touchable/TouchableOpacity', (props) => {
23 return {
24 onPress: props.disabled ? () => {} : props.onPress
25 }
26 })
27})
28
29jest.mock('react-native/Libraries/Components/Touchable/TouchableOpacity', () => {
30 return <MockComponent
31 module='TouchableOpacity'
32 onPress={props => props.disabled ? () => {} : props.onPress}
33 />
34})
35
36jest.mock('react-native/Libraries/Components/Touchable/TouchableOpacity', () => {
37 return <MockComponent
38 module='TouchableOpacity'
39 propOverride={props => ({onPress: props.disabled ? () => {} : props.onPress, ...props})}
40 />
41})
42// https://learn.reactnativeschool.com/courses/781007/lectures/14173979
43export function MockComponent(props) {
44 const { moduleName, propOverrideFn, ...customComponentProps } = props;
45
46 const RealComponent = jest.requireActual(moduleName) as React.ComponentType<any>
47 const CustomizedComponent = (props: Record<string, any>) => {
48 return React.createElement(
49 'CustomizedComponent',
50 {
51 ...props,
52 ...propOverrideFn(props),
53 },
54 props.children
55 )
56 }
57 CustomizedComponent.propTypes = RealComponent.propTypes
58
59 return <CustomizedComponent {...customComponentProps} />
60}
61
The differences are subtle but important. Here I modified MockComponent
to take in a singular prop
argument to be compatible with React.createElement()
. This leads to the issue of how to differentiate props that are meant for the CustomizedComponent
and what used to be arguments for mockComponent()
. Here, I use the JavaScript destructuring and spread operators to separate module
and propOverride
from the props intended from CustomizedComponent
.
Lastly, I use the JSX spread syntax to pass the arbitrary props intended for CustomizedComponent
into CustomizedComponent
, and I use angle brackets to render it (instead of returning a function).
I'll leave as an exercise for you to come up with the appropriate TypeScript definition for MockComponent's props. You can simply define it as the union of Record<string, any> and module
and propOverride
. However, you can get fancy and use a template definition so MockComponent<Toolbar>
is a union of module
and propOverride
and Toolbar
's props.
Oh, and I almost forgot. Your Jest call would look like
1import { jest } from '@jest/globals'
2import React from 'react'
3
4// https://learn.reactnativeschool.com/courses/781007/lectures/14173979
5export function mockComponent(moduleName: string, propOverrideFn = (props: Record<string, any>) => ({})) {
6 const RealComponent = jest.requireActual(moduleName) as React.ComponentType<any>
7 const CustomizedComponent = (props: Record<string, any>) => {
8 return React.createElement(
9 'CustomizedComponent',
10 {
11 ...props,
12 ...propOverrideFn(props),
13 },
14 props.children
15 )
16 }
17 CustomizedComponent.propTypes = RealComponent.propTypes
18
19 return CustomizedComponent
20}
21jest.mock('react-native/Libraries/Components/Touchable/TouchableOpacity', () => {
22 return mockComponent('react-native/Libraries/Components/Touchable/TouchableOpacity', (props) => {
23 return {
24 onPress: props.disabled ? () => {} : props.onPress
25 }
26 })
27})
28
29jest.mock('react-native/Libraries/Components/Touchable/TouchableOpacity', () => {
30 return <MockComponent
31 module='TouchableOpacity'
32 onPress={props => props.disabled ? () => {} : props.onPress}
33 />
34})
35
36jest.mock('react-native/Libraries/Components/Touchable/TouchableOpacity', () => {
37 return <MockComponent
38 module='TouchableOpacity'
39 propOverride={props => ({onPress: props.disabled ? () => {} : props.onPress, ...props})}
40 />
41})
42// https://learn.reactnativeschool.com/courses/781007/lectures/14173979
43export function MockComponent(props) {
44 const { moduleName, propOverrideFn, ...customComponentProps } = props;
45
46 const RealComponent = jest.requireActual(moduleName) as React.ComponentType<any>
47 const CustomizedComponent = (props: Record<string, any>) => {
48 return React.createElement(
49 'CustomizedComponent',
50 {
51 ...props,
52 ...propOverrideFn(props),
53 },
54 props.children
55 )
56 }
57 CustomizedComponent.propTypes = RealComponent.propTypes
58
59 return <CustomizedComponent {...customComponentProps} />
60}
61jest.mock('react-native/Libraries/Components/Touchable/TouchableOpacity', () => {
62 (props) => {
63 return <MockComponent
64 module='TouchableOpacity'
65 onPress={props => props.disabled ? () => {} : props.onPress}
66 {...props}
67 />
68 }
69})
70
QUESTION
Can not instantiate proxy of class: System.Net.HttpWebRequest. Could not find a parameterless constructor
Asked 2022-Feb-23 at 12:05I am upgrading my C#
function app from .net 3.1 to 6.0`.
When I run my test cases, I found that, 1 of my test case failed with the below error.
Castle.DynamicProxy.InvalidProxyConstructorArgumentsException : Can not instantiate proxy of class: System.Net.HttpWebRequest. Could not find a parameterless constructor.
Basically, I am trying to mock HttpWebRequest and below is my piece of code for that.
1var httpWebRequest = new Mock<HttpWebRequest>();
2
It is working fine in .Net 3.1. I am using Moq version 4.16.1 in both the projects.
ANSWER
Answered 2022-Feb-23 at 10:53Both HttpWebRequest constructors are obsolete and should not be used. You have to use the static function "Create" to create a new instance of the HttpWebRequest class:
HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create("http://www.contoso.com/");
To solve your issue, use the HttpClient class instead. This class has a parameterless constructor.
QUESTION
Apache Beam Cloud Dataflow Streaming Stuck Side Input
Asked 2022-Jan-12 at 13:12I'm currently building PoC Apache Beam pipeline in GCP Dataflow. In this case, I want to create streaming pipeline with main input from PubSub and side input from BigQuery and store processed data back to BigQuery.
Side pipeline code
1side_pipeline = (
2 p
3 | "periodic" >> PeriodicImpulse(fire_interval=3600, apply_windowing=True)
4 | "map to read request" >>
5 beam.Map(lambda x:beam.io.gcp.bigquery.ReadFromBigQueryRequest(table=side_table))
6 | beam.io.ReadAllFromBigQuery()
7)
8
Function with side input code
1side_pipeline = (
2 p
3 | "periodic" >> PeriodicImpulse(fire_interval=3600, apply_windowing=True)
4 | "map to read request" >>
5 beam.Map(lambda x:beam.io.gcp.bigquery.ReadFromBigQueryRequest(table=side_table))
6 | beam.io.ReadAllFromBigQuery()
7)
8def enrich_payload(payload, equipments):
9 id = payload["id"]
10 for equipment in equipments:
11 if id == equipment["id"]:
12 payload["type"] = equipment["type"]
13 payload["brand"] = equipment["brand"]
14 payload["year"] = equipment["year"]
15
16 break
17
18 return payload
19
Main pipeline code
1side_pipeline = (
2 p
3 | "periodic" >> PeriodicImpulse(fire_interval=3600, apply_windowing=True)
4 | "map to read request" >>
5 beam.Map(lambda x:beam.io.gcp.bigquery.ReadFromBigQueryRequest(table=side_table))
6 | beam.io.ReadAllFromBigQuery()
7)
8def enrich_payload(payload, equipments):
9 id = payload["id"]
10 for equipment in equipments:
11 if id == equipment["id"]:
12 payload["type"] = equipment["type"]
13 payload["brand"] = equipment["brand"]
14 payload["year"] = equipment["year"]
15
16 break
17
18 return payload
19main_pipeline = (
20 p
21 | "read" >> beam.io.ReadFromPubSub(topic="projects/my-project/topics/topiq")
22 | "bytes to dict" >> beam.Map(lambda x: json.loads(x.decode("utf-8")))
23 | "transform" >> beam.Map(transform_function)
24 | "timestamping" >> beam.Map(lambda src: window.TimestampedValue(
25 src,
26 dt.datetime.fromisoformat(src["timestamp"]).timestamp()
27 ))
28 | "windowing" >> beam.WindowInto(window.FixedWindows(30))
29)
30
31final_pipeline = (
32 main_pipeline
33 | "enrich data" >> beam.Map(enrich_payload, equipments=beam.pvalue.AsIter(side_pipeline))
34 | "store" >> beam.io.WriteToBigQuery(bq_table)
35)
36
37result = p.run()
38result.wait_until_finish()
39
After deploy it to Dataflow, everything looks fine and no error. But then I noticed that enrich data
step has two nodes instead of one.
And also, the side input stuck as you can see it has Elements Added
with 21 counts in Input Collections and -
value in Elements Added
in Output Collections.
You can find the full pipeline code here and mock pubsub publisher here
I already follow all instruction in these documentations:
- https://beam.apache.org/documentation/patterns/side-inputs/
- https://beam.apache.org/releases/pydoc/2.35.0/apache_beam.io.gcp.bigquery.html
Yet still found this error. Please help me. Thanks!
ANSWER
Answered 2022-Jan-12 at 13:12Here you have a working example:
1side_pipeline = (
2 p
3 | "periodic" >> PeriodicImpulse(fire_interval=3600, apply_windowing=True)
4 | "map to read request" >>
5 beam.Map(lambda x:beam.io.gcp.bigquery.ReadFromBigQueryRequest(table=side_table))
6 | beam.io.ReadAllFromBigQuery()
7)
8def enrich_payload(payload, equipments):
9 id = payload["id"]
10 for equipment in equipments:
11 if id == equipment["id"]:
12 payload["type"] = equipment["type"]
13 payload["brand"] = equipment["brand"]
14 payload["year"] = equipment["year"]
15
16 break
17
18 return payload
19main_pipeline = (
20 p
21 | "read" >> beam.io.ReadFromPubSub(topic="projects/my-project/topics/topiq")
22 | "bytes to dict" >> beam.Map(lambda x: json.loads(x.decode("utf-8")))
23 | "transform" >> beam.Map(transform_function)
24 | "timestamping" >> beam.Map(lambda src: window.TimestampedValue(
25 src,
26 dt.datetime.fromisoformat(src["timestamp"]).timestamp()
27 ))
28 | "windowing" >> beam.WindowInto(window.FixedWindows(30))
29)
30
31final_pipeline = (
32 main_pipeline
33 | "enrich data" >> beam.Map(enrich_payload, equipments=beam.pvalue.AsIter(side_pipeline))
34 | "store" >> beam.io.WriteToBigQuery(bq_table)
35)
36
37result = p.run()
38result.wait_until_finish()
39mytopic = ""
40sql = "SELECT station_id, CURRENT_TIMESTAMP() timestamp FROM `bigquery-public-data.austin_bikeshare.bikeshare_stations` LIMIT 10"
41
42def to_bqrequest(e, sql):
43 from apache_beam.io import ReadFromBigQueryRequest
44 yield ReadFromBigQueryRequest(query=sql)
45
46
47def merge(e, side):
48 for i in side:
49 yield f"Main {e.decode('utf-8')} Side {i}"
50
51pubsub = p | "Read PubSub topic" >> ReadFromPubSub(topic=mytopic)
52
53side_pcol = (p | PeriodicImpulse(fire_interval=300, apply_windowing=False)
54 | "ApplyGlobalWindow" >> WindowInto(window.GlobalWindows(),
55 trigger=trigger.Repeatedly(trigger.AfterProcessingTime(5)),
56 accumulation_mode=trigger.AccumulationMode.DISCARDING)
57 | "To BQ Request" >> ParDo(to_bqrequest, sql=sql)
58 | ReadAllFromBigQuery()
59 )
60
61final = (pubsub | "Merge" >> ParDo(merge, side=beam.pvalue.AsList(side_pcol))
62 | Map(logging.info)
63 )
64
65p.run()
66
Note this uses a GlobalWindow
(so that both inputs have the same window). I used a processing time trigger so that the pane contains multiple rows. 5
was chosen arbitrarily, using 1
would work too.
Please note matching the data between side and main inputs is non deterministic, and you may see fluctuating values from older fired panes.
In theory, using FixedWindows
should fix this, but I cannot get the FixedWindows
to work.
QUESTION
How to compare file paths from JsonConfigurationSources and Directory.GetFiles properly?
Asked 2021-Dec-20 at 04:22I created an extension method to add all JSON configuration files to the IConfigurationBuilder
1public static class IConfigurationBuilderExtensions
2{
3 public static IConfigurationBuilder AddJsonFilesFromDirectory(
4 this IConfigurationBuilder configurationBuilder,
5 IFileSystem fileSystem,
6 string pathToDirectory,
7 bool fileIsOptional,
8 bool reloadConfigurationOnFileChange,
9 string searchPattern = "*.json",
10 SearchOption directorySearchOption = SearchOption.AllDirectories)
11 {
12 var jsonFilePaths = fileSystem.Directory.EnumerateFiles(pathToDirectory, searchPattern, directorySearchOption);
13
14 foreach (var jsonFilePath in jsonFilePaths)
15 {
16 configurationBuilder.AddJsonFile(jsonFilePath, fileIsOptional, reloadConfigurationOnFileChange);
17 }
18
19 return configurationBuilder;
20 }
21}
22
and want to create tests for it using xUnit. Based on
How do you mock out the file system in C# for unit testing?
I installed the packages System.IO.Abstractions and System.IO.Abstractions.TestingHelpers and started to test that JSON files from directories have been added
1public static class IConfigurationBuilderExtensions
2{
3 public static IConfigurationBuilder AddJsonFilesFromDirectory(
4 this IConfigurationBuilder configurationBuilder,
5 IFileSystem fileSystem,
6 string pathToDirectory,
7 bool fileIsOptional,
8 bool reloadConfigurationOnFileChange,
9 string searchPattern = "*.json",
10 SearchOption directorySearchOption = SearchOption.AllDirectories)
11 {
12 var jsonFilePaths = fileSystem.Directory.EnumerateFiles(pathToDirectory, searchPattern, directorySearchOption);
13
14 foreach (var jsonFilePath in jsonFilePaths)
15 {
16 configurationBuilder.AddJsonFile(jsonFilePath, fileIsOptional, reloadConfigurationOnFileChange);
17 }
18
19 return configurationBuilder;
20 }
21}
22public sealed class IConfigurationBuilderExtensionsTests
23{
24 private const string DirectoryRootPath = "./";
25
26 private readonly MockFileSystem _fileSystem;
27
28 public IConfigurationBuilderExtensionsTests()
29 {
30 _fileSystem = new MockFileSystem(new[]
31 {
32 "text.txt",
33 "config.json",
34 "dir/foo.json",
35 "dir/bar.xml",
36 "dir/sub/deeper/config.json"
37 }
38 .Select(filePath => Path.Combine(DirectoryRootPath, filePath))
39 .ToDictionary(
40 filePath => filePath,
41 _ => new MockFileData(string.Empty)));
42 }
43
44 [Theory]
45 [InlineData("*.json", SearchOption.AllDirectories)]
46 [InlineData("*.json", SearchOption.TopDirectoryOnly)]
47 // ... more theories go here ...
48 public void ItShouldAddJsonFilesFromDirectory(string searchPattern, SearchOption searchOption)
49 {
50 var addedJsonFilePaths = new ConfigurationBuilder()
51 .AddJsonFilesFromDirectory(_fileSystem, DirectoryRootPath, true, true, searchPattern, searchOption)
52 .Sources
53 .OfType<JsonConfigurationSource>()
54 .Select(jsonConfigurationSource => jsonConfigurationSource.Path)
55 .ToArray();
56
57 var jsonFilePathsFromTopDirectory = _fileSystem.Directory.GetFiles(DirectoryRootPath, searchPattern, searchOption);
58
59 Assert.True(addedJsonFilePaths.Length == jsonFilePathsFromTopDirectory.Length);
60
61 for (int i = 0; i < addedJsonFilePaths.Length; i++)
62 {
63 Assert.Equal(
64 jsonFilePathsFromTopDirectory[i],
65 Path.DirectorySeparatorChar + addedJsonFilePaths[i]);
66 }
67 }
68}
69
The tests are passing but I would like to know if I could get in trouble when prepending Path.DirectorySeparatorChar
to addedJsonFilePaths[i]
.
The problem is that
jsonFilePathsFromTopDirectory[i]
returns "/config.json"addedJsonFilePaths[i]
returns "config.json"
so I have to prepend a slash at the beginning. Do you have any suggestions how to improve this / avoid later problems?
ANSWER
Answered 2021-Dec-19 at 09:24The logic of comparing files seems alright, I don't find any outstanding problem with it, it is ok to prepend the "/" to match what you need.
Could be even better if you could use the System.IO.Path.DirectorySeparatorChar
for the directory root path as well, so if you run on windows or Linux you will have no issues.
But there may be a conceptual problem with what you are doing. To my understanding you aim to verify existence of specific configuration files required for your program to work right, if those files are missing than the program should fail. But that kind of failure due to missing configuration files, is an expected and valid result of your code. Yet, you unit-test this as if missing files should fail the test, as if missing files are an indication that something wrong with your code, this is wrong.
Missing files are not indication of your code not working correct and Unit-test should not be used as a validator to make sure the files exist prior executing the program, you will likely agree that unit-test is not part of the actual process and it should only aim to test your code and not preconditions, the test should compare an expected result (mock result of your code) vs. actual result and certainly not meant to become part of the code. That unit test looks like a validator that should be in the code.
So unless those files are produced by your specific code (and not the deployment) there is no sense testing that. In such case you need to create a configuration validator code - and your unit test could test that instead. So it will test that the validator expected result with a mock input you provide. But the thing here is that you would know that you only testing the validation logic and not the actual existence of the files.
QUESTION
How to get preview in composable functions that depend on a view model?
Asked 2021-Dec-16 at 21:53I would like to have the preview of my HomeScreen
composable function in my HomeScreenPrevieiw
preview function. However this is not being possible to do because I am getting the following error:
1java.lang.IllegalStateException: ViewModels creation is not supported in Preview
2 at androidx.compose.ui.tooling.ComposeViewAdapter$FakeViewModelStoreOwner$1.getViewModelStore(ComposeViewAdapter.kt:709)
3 at androidx.lifecycle.ViewModelProvider.<init>(ViewModelProvider.kt:105)
4 at androidx.lifecycle.viewmodel.compose.ViewModelKt.get(ViewModel.kt:82)
5 at androidx.lifecycle.viewmodel.compose.ViewModelKt.viewModel(ViewModel.kt:72)
6 at com.example.crud.ui.screens.home.HomeScreenKt.HomeScreen(HomeScreen.kt:53)
7 at com.example.crud.ui.screens.home.HomeScreenKt.HomeScreenPreview(HomeScreen.kt:43)
8 at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
9 at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
10 ...
11
This is my HomeScreen
code:
1java.lang.IllegalStateException: ViewModels creation is not supported in Preview
2 at androidx.compose.ui.tooling.ComposeViewAdapter$FakeViewModelStoreOwner$1.getViewModelStore(ComposeViewAdapter.kt:709)
3 at androidx.lifecycle.ViewModelProvider.<init>(ViewModelProvider.kt:105)
4 at androidx.lifecycle.viewmodel.compose.ViewModelKt.get(ViewModel.kt:82)
5 at androidx.lifecycle.viewmodel.compose.ViewModelKt.viewModel(ViewModel.kt:72)
6 at com.example.crud.ui.screens.home.HomeScreenKt.HomeScreen(HomeScreen.kt:53)
7 at com.example.crud.ui.screens.home.HomeScreenKt.HomeScreenPreview(HomeScreen.kt:43)
8 at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
9 at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
10 ...
11@Composable
12fun HomeScreen(
13 viewModel: HomeViewModel = hiltViewModel(),
14 navigateToDetailsAction: () -> Unit,
15 openCardDetailsAction: (Int) -> Unit
16) {
17 val cities = viewModel.cities.observeAsState(listOf())
18 Scaffold(
19 topBar = { HomeAppBar() },
20 floatingActionButton = { HomeFab(navigateToDetailsAction) }
21 ) {
22 HomeContent(cities) { id -> openCardDetailsAction(id) }
23 }
24}
25
This is the code for my preview function:
1java.lang.IllegalStateException: ViewModels creation is not supported in Preview
2 at androidx.compose.ui.tooling.ComposeViewAdapter$FakeViewModelStoreOwner$1.getViewModelStore(ComposeViewAdapter.kt:709)
3 at androidx.lifecycle.ViewModelProvider.<init>(ViewModelProvider.kt:105)
4 at androidx.lifecycle.viewmodel.compose.ViewModelKt.get(ViewModel.kt:82)
5 at androidx.lifecycle.viewmodel.compose.ViewModelKt.viewModel(ViewModel.kt:72)
6 at com.example.crud.ui.screens.home.HomeScreenKt.HomeScreen(HomeScreen.kt:53)
7 at com.example.crud.ui.screens.home.HomeScreenKt.HomeScreenPreview(HomeScreen.kt:43)
8 at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
9 at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
10 ...
11@Composable
12fun HomeScreen(
13 viewModel: HomeViewModel = hiltViewModel(),
14 navigateToDetailsAction: () -> Unit,
15 openCardDetailsAction: (Int) -> Unit
16) {
17 val cities = viewModel.cities.observeAsState(listOf())
18 Scaffold(
19 topBar = { HomeAppBar() },
20 floatingActionButton = { HomeFab(navigateToDetailsAction) }
21 ) {
22 HomeContent(cities) { id -> openCardDetailsAction(id) }
23 }
24}
25@Preview
26@Composable
27private fun HomeScreenPreview() {
28 HomeScreen(navigateToDetailsAction = {}, openCardDetailsAction = {})
29}
30
My view model:
1java.lang.IllegalStateException: ViewModels creation is not supported in Preview
2 at androidx.compose.ui.tooling.ComposeViewAdapter$FakeViewModelStoreOwner$1.getViewModelStore(ComposeViewAdapter.kt:709)
3 at androidx.lifecycle.ViewModelProvider.<init>(ViewModelProvider.kt:105)
4 at androidx.lifecycle.viewmodel.compose.ViewModelKt.get(ViewModel.kt:82)
5 at androidx.lifecycle.viewmodel.compose.ViewModelKt.viewModel(ViewModel.kt:72)
6 at com.example.crud.ui.screens.home.HomeScreenKt.HomeScreen(HomeScreen.kt:53)
7 at com.example.crud.ui.screens.home.HomeScreenKt.HomeScreenPreview(HomeScreen.kt:43)
8 at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
9 at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
10 ...
11@Composable
12fun HomeScreen(
13 viewModel: HomeViewModel = hiltViewModel(),
14 navigateToDetailsAction: () -> Unit,
15 openCardDetailsAction: (Int) -> Unit
16) {
17 val cities = viewModel.cities.observeAsState(listOf())
18 Scaffold(
19 topBar = { HomeAppBar() },
20 floatingActionButton = { HomeFab(navigateToDetailsAction) }
21 ) {
22 HomeContent(cities) { id -> openCardDetailsAction(id) }
23 }
24}
25@Preview
26@Composable
27private fun HomeScreenPreview() {
28 HomeScreen(navigateToDetailsAction = {}, openCardDetailsAction = {})
29}
30@HiltViewModel
31class HomeViewModel @Inject constructor(repository: CityRepository) : ViewModel() {
32 val cities: LiveData<List<City>> = repository.allCities.asLiveData()
33}
34
Repository:
1java.lang.IllegalStateException: ViewModels creation is not supported in Preview
2 at androidx.compose.ui.tooling.ComposeViewAdapter$FakeViewModelStoreOwner$1.getViewModelStore(ComposeViewAdapter.kt:709)
3 at androidx.lifecycle.ViewModelProvider.<init>(ViewModelProvider.kt:105)
4 at androidx.lifecycle.viewmodel.compose.ViewModelKt.get(ViewModel.kt:82)
5 at androidx.lifecycle.viewmodel.compose.ViewModelKt.viewModel(ViewModel.kt:72)
6 at com.example.crud.ui.screens.home.HomeScreenKt.HomeScreen(HomeScreen.kt:53)
7 at com.example.crud.ui.screens.home.HomeScreenKt.HomeScreenPreview(HomeScreen.kt:43)
8 at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
9 at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
10 ...
11@Composable
12fun HomeScreen(
13 viewModel: HomeViewModel = hiltViewModel(),
14 navigateToDetailsAction: () -> Unit,
15 openCardDetailsAction: (Int) -> Unit
16) {
17 val cities = viewModel.cities.observeAsState(listOf())
18 Scaffold(
19 topBar = { HomeAppBar() },
20 floatingActionButton = { HomeFab(navigateToDetailsAction) }
21 ) {
22 HomeContent(cities) { id -> openCardDetailsAction(id) }
23 }
24}
25@Preview
26@Composable
27private fun HomeScreenPreview() {
28 HomeScreen(navigateToDetailsAction = {}, openCardDetailsAction = {})
29}
30@HiltViewModel
31class HomeViewModel @Inject constructor(repository: CityRepository) : ViewModel() {
32 val cities: LiveData<List<City>> = repository.allCities.asLiveData()
33}
34@ViewModelScoped
35class CityRepository @Inject constructor(appDatabase: AppDatabase) {
36 private val dao by lazy { appDatabase.getCityDao() }
37
38 val allCities by lazy { dao.getAllCities() }
39
40 suspend fun addCity(city: City) = dao.insert(city)
41
42 suspend fun updateCity(city: City) = dao.update(city)
43
44 suspend fun deleteCity(city: City) = dao.delete(city)
45
46 suspend fun getCityById(id: Int) = dao.getCityById(id)
47
48}
49
AppDatabase:
1java.lang.IllegalStateException: ViewModels creation is not supported in Preview
2 at androidx.compose.ui.tooling.ComposeViewAdapter$FakeViewModelStoreOwner$1.getViewModelStore(ComposeViewAdapter.kt:709)
3 at androidx.lifecycle.ViewModelProvider.<init>(ViewModelProvider.kt:105)
4 at androidx.lifecycle.viewmodel.compose.ViewModelKt.get(ViewModel.kt:82)
5 at androidx.lifecycle.viewmodel.compose.ViewModelKt.viewModel(ViewModel.kt:72)
6 at com.example.crud.ui.screens.home.HomeScreenKt.HomeScreen(HomeScreen.kt:53)
7 at com.example.crud.ui.screens.home.HomeScreenKt.HomeScreenPreview(HomeScreen.kt:43)
8 at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
9 at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
10 ...
11@Composable
12fun HomeScreen(
13 viewModel: HomeViewModel = hiltViewModel(),
14 navigateToDetailsAction: () -> Unit,
15 openCardDetailsAction: (Int) -> Unit
16) {
17 val cities = viewModel.cities.observeAsState(listOf())
18 Scaffold(
19 topBar = { HomeAppBar() },
20 floatingActionButton = { HomeFab(navigateToDetailsAction) }
21 ) {
22 HomeContent(cities) { id -> openCardDetailsAction(id) }
23 }
24}
25@Preview
26@Composable
27private fun HomeScreenPreview() {
28 HomeScreen(navigateToDetailsAction = {}, openCardDetailsAction = {})
29}
30@HiltViewModel
31class HomeViewModel @Inject constructor(repository: CityRepository) : ViewModel() {
32 val cities: LiveData<List<City>> = repository.allCities.asLiveData()
33}
34@ViewModelScoped
35class CityRepository @Inject constructor(appDatabase: AppDatabase) {
36 private val dao by lazy { appDatabase.getCityDao() }
37
38 val allCities by lazy { dao.getAllCities() }
39
40 suspend fun addCity(city: City) = dao.insert(city)
41
42 suspend fun updateCity(city: City) = dao.update(city)
43
44 suspend fun deleteCity(city: City) = dao.delete(city)
45
46 suspend fun getCityById(id: Int) = dao.getCityById(id)
47
48}
49@Database(entities = [City::class], version = 2, exportSchema = false)
50abstract class AppDatabase : RoomDatabase() {
51 abstract fun getCityDao() : CityDao
52}
53
I thought it might be a problem with the view model being passed as the default parameter of my HomeScreen
and so I decided to do it this way:
1java.lang.IllegalStateException: ViewModels creation is not supported in Preview
2 at androidx.compose.ui.tooling.ComposeViewAdapter$FakeViewModelStoreOwner$1.getViewModelStore(ComposeViewAdapter.kt:709)
3 at androidx.lifecycle.ViewModelProvider.<init>(ViewModelProvider.kt:105)
4 at androidx.lifecycle.viewmodel.compose.ViewModelKt.get(ViewModel.kt:82)
5 at androidx.lifecycle.viewmodel.compose.ViewModelKt.viewModel(ViewModel.kt:72)
6 at com.example.crud.ui.screens.home.HomeScreenKt.HomeScreen(HomeScreen.kt:53)
7 at com.example.crud.ui.screens.home.HomeScreenKt.HomeScreenPreview(HomeScreen.kt:43)
8 at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
9 at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
10 ...
11@Composable
12fun HomeScreen(
13 viewModel: HomeViewModel = hiltViewModel(),
14 navigateToDetailsAction: () -> Unit,
15 openCardDetailsAction: (Int) -> Unit
16) {
17 val cities = viewModel.cities.observeAsState(listOf())
18 Scaffold(
19 topBar = { HomeAppBar() },
20 floatingActionButton = { HomeFab(navigateToDetailsAction) }
21 ) {
22 HomeContent(cities) { id -> openCardDetailsAction(id) }
23 }
24}
25@Preview
26@Composable
27private fun HomeScreenPreview() {
28 HomeScreen(navigateToDetailsAction = {}, openCardDetailsAction = {})
29}
30@HiltViewModel
31class HomeViewModel @Inject constructor(repository: CityRepository) : ViewModel() {
32 val cities: LiveData<List<City>> = repository.allCities.asLiveData()
33}
34@ViewModelScoped
35class CityRepository @Inject constructor(appDatabase: AppDatabase) {
36 private val dao by lazy { appDatabase.getCityDao() }
37
38 val allCities by lazy { dao.getAllCities() }
39
40 suspend fun addCity(city: City) = dao.insert(city)
41
42 suspend fun updateCity(city: City) = dao.update(city)
43
44 suspend fun deleteCity(city: City) = dao.delete(city)
45
46 suspend fun getCityById(id: Int) = dao.getCityById(id)
47
48}
49@Database(entities = [City::class], version = 2, exportSchema = false)
50abstract class AppDatabase : RoomDatabase() {
51 abstract fun getCityDao() : CityDao
52}
53@Composable
54fun HomeScreen(
55 navigateToDetailsAction: () -> Unit,
56 openCardDetailsAction: (Int) -> Unit
57) {
58 val viewModel: HomeViewModel = hiltViewModel()
59 val cities = viewModel.cities.observeAsState(listOf())
60 Scaffold(
61 topBar = { HomeAppBar() },
62 floatingActionButton = { HomeFab(navigateToDetailsAction) }
63 ) {
64 HomeContent(cities) { id -> openCardDetailsAction(id) }
65 }
66}
67
But it still doesn't work (I keep getting the same error), and it's not good for testing as it would prevent me from testing my HomeScreen
with a mocked view model.
ANSWER
Answered 2021-Sep-07 at 16:48This is exactly one of the reasons why the view model is passed with a default value. In the preview, you can pass a test object:
1java.lang.IllegalStateException: ViewModels creation is not supported in Preview
2 at androidx.compose.ui.tooling.ComposeViewAdapter$FakeViewModelStoreOwner$1.getViewModelStore(ComposeViewAdapter.kt:709)
3 at androidx.lifecycle.ViewModelProvider.<init>(ViewModelProvider.kt:105)
4 at androidx.lifecycle.viewmodel.compose.ViewModelKt.get(ViewModel.kt:82)
5 at androidx.lifecycle.viewmodel.compose.ViewModelKt.viewModel(ViewModel.kt:72)
6 at com.example.crud.ui.screens.home.HomeScreenKt.HomeScreen(HomeScreen.kt:53)
7 at com.example.crud.ui.screens.home.HomeScreenKt.HomeScreenPreview(HomeScreen.kt:43)
8 at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
9 at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
10 ...
11@Composable
12fun HomeScreen(
13 viewModel: HomeViewModel = hiltViewModel(),
14 navigateToDetailsAction: () -> Unit,
15 openCardDetailsAction: (Int) -> Unit
16) {
17 val cities = viewModel.cities.observeAsState(listOf())
18 Scaffold(
19 topBar = { HomeAppBar() },
20 floatingActionButton = { HomeFab(navigateToDetailsAction) }
21 ) {
22 HomeContent(cities) { id -> openCardDetailsAction(id) }
23 }
24}
25@Preview
26@Composable
27private fun HomeScreenPreview() {
28 HomeScreen(navigateToDetailsAction = {}, openCardDetailsAction = {})
29}
30@HiltViewModel
31class HomeViewModel @Inject constructor(repository: CityRepository) : ViewModel() {
32 val cities: LiveData<List<City>> = repository.allCities.asLiveData()
33}
34@ViewModelScoped
35class CityRepository @Inject constructor(appDatabase: AppDatabase) {
36 private val dao by lazy { appDatabase.getCityDao() }
37
38 val allCities by lazy { dao.getAllCities() }
39
40 suspend fun addCity(city: City) = dao.insert(city)
41
42 suspend fun updateCity(city: City) = dao.update(city)
43
44 suspend fun deleteCity(city: City) = dao.delete(city)
45
46 suspend fun getCityById(id: Int) = dao.getCityById(id)
47
48}
49@Database(entities = [City::class], version = 2, exportSchema = false)
50abstract class AppDatabase : RoomDatabase() {
51 abstract fun getCityDao() : CityDao
52}
53@Composable
54fun HomeScreen(
55 navigateToDetailsAction: () -> Unit,
56 openCardDetailsAction: (Int) -> Unit
57) {
58 val viewModel: HomeViewModel = hiltViewModel()
59 val cities = viewModel.cities.observeAsState(listOf())
60 Scaffold(
61 topBar = { HomeAppBar() },
62 floatingActionButton = { HomeFab(navigateToDetailsAction) }
63 ) {
64 HomeContent(cities) { id -> openCardDetailsAction(id) }
65 }
66}
67@Preview
68@Composable
69private fun HomeScreenPreview() {
70 val viewModel = HomeViewModel()
71 // setup viewModel as you need it to be in the preview
72 HomeScreen(viewModel = viewModel, navigateToDetailsAction = {}, openCardDetailsAction = {})
73}
74
Since you have a repository, you can do the same thing you would do to test the view model.
- Create interface for
CityRepository
1java.lang.IllegalStateException: ViewModels creation is not supported in Preview
2 at androidx.compose.ui.tooling.ComposeViewAdapter$FakeViewModelStoreOwner$1.getViewModelStore(ComposeViewAdapter.kt:709)
3 at androidx.lifecycle.ViewModelProvider.<init>(ViewModelProvider.kt:105)
4 at androidx.lifecycle.viewmodel.compose.ViewModelKt.get(ViewModel.kt:82)
5 at androidx.lifecycle.viewmodel.compose.ViewModelKt.viewModel(ViewModel.kt:72)
6 at com.example.crud.ui.screens.home.HomeScreenKt.HomeScreen(HomeScreen.kt:53)
7 at com.example.crud.ui.screens.home.HomeScreenKt.HomeScreenPreview(HomeScreen.kt:43)
8 at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
9 at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
10 ...
11@Composable
12fun HomeScreen(
13 viewModel: HomeViewModel = hiltViewModel(),
14 navigateToDetailsAction: () -> Unit,
15 openCardDetailsAction: (Int) -> Unit
16) {
17 val cities = viewModel.cities.observeAsState(listOf())
18 Scaffold(
19 topBar = { HomeAppBar() },
20 floatingActionButton = { HomeFab(navigateToDetailsAction) }
21 ) {
22 HomeContent(cities) { id -> openCardDetailsAction(id) }
23 }
24}
25@Preview
26@Composable
27private fun HomeScreenPreview() {
28 HomeScreen(navigateToDetailsAction = {}, openCardDetailsAction = {})
29}
30@HiltViewModel
31class HomeViewModel @Inject constructor(repository: CityRepository) : ViewModel() {
32 val cities: LiveData<List<City>> = repository.allCities.asLiveData()
33}
34@ViewModelScoped
35class CityRepository @Inject constructor(appDatabase: AppDatabase) {
36 private val dao by lazy { appDatabase.getCityDao() }
37
38 val allCities by lazy { dao.getAllCities() }
39
40 suspend fun addCity(city: City) = dao.insert(city)
41
42 suspend fun updateCity(city: City) = dao.update(city)
43
44 suspend fun deleteCity(city: City) = dao.delete(city)
45
46 suspend fun getCityById(id: Int) = dao.getCityById(id)
47
48}
49@Database(entities = [City::class], version = 2, exportSchema = false)
50abstract class AppDatabase : RoomDatabase() {
51 abstract fun getCityDao() : CityDao
52}
53@Composable
54fun HomeScreen(
55 navigateToDetailsAction: () -> Unit,
56 openCardDetailsAction: (Int) -> Unit
57) {
58 val viewModel: HomeViewModel = hiltViewModel()
59 val cities = viewModel.cities.observeAsState(listOf())
60 Scaffold(
61 topBar = { HomeAppBar() },
62 floatingActionButton = { HomeFab(navigateToDetailsAction) }
63 ) {
64 HomeContent(cities) { id -> openCardDetailsAction(id) }
65 }
66}
67@Preview
68@Composable
69private fun HomeScreenPreview() {
70 val viewModel = HomeViewModel()
71 // setup viewModel as you need it to be in the preview
72 HomeScreen(viewModel = viewModel, navigateToDetailsAction = {}, openCardDetailsAction = {})
73}
74interface CityRepositoryI {
75 val allCities: List<City>
76
77 suspend fun addCity(city: City)
78 suspend fun updateCity(city: City)
79 suspend fun deleteCity(city: City)
80 suspend fun getCityById(id: Int)
81}
82
- Implement it for
CityRepository
:
1java.lang.IllegalStateException: ViewModels creation is not supported in Preview
2 at androidx.compose.ui.tooling.ComposeViewAdapter$FakeViewModelStoreOwner$1.getViewModelStore(ComposeViewAdapter.kt:709)
3 at androidx.lifecycle.ViewModelProvider.<init>(ViewModelProvider.kt:105)
4 at androidx.lifecycle.viewmodel.compose.ViewModelKt.get(ViewModel.kt:82)
5 at androidx.lifecycle.viewmodel.compose.ViewModelKt.viewModel(ViewModel.kt:72)
6 at com.example.crud.ui.screens.home.HomeScreenKt.HomeScreen(HomeScreen.kt:53)
7 at com.example.crud.ui.screens.home.HomeScreenKt.HomeScreenPreview(HomeScreen.kt:43)
8 at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
9 at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
10 ...
11@Composable
12fun HomeScreen(
13 viewModel: HomeViewModel = hiltViewModel(),
14 navigateToDetailsAction: () -> Unit,
15 openCardDetailsAction: (Int) -> Unit
16) {
17 val cities = viewModel.cities.observeAsState(listOf())
18 Scaffold(
19 topBar = { HomeAppBar() },
20 floatingActionButton = { HomeFab(navigateToDetailsAction) }
21 ) {
22 HomeContent(cities) { id -> openCardDetailsAction(id) }
23 }
24}
25@Preview
26@Composable
27private fun HomeScreenPreview() {
28 HomeScreen(navigateToDetailsAction = {}, openCardDetailsAction = {})
29}
30@HiltViewModel
31class HomeViewModel @Inject constructor(repository: CityRepository) : ViewModel() {
32 val cities: LiveData<List<City>> = repository.allCities.asLiveData()
33}
34@ViewModelScoped
35class CityRepository @Inject constructor(appDatabase: AppDatabase) {
36 private val dao by lazy { appDatabase.getCityDao() }
37
38 val allCities by lazy { dao.getAllCities() }
39
40 suspend fun addCity(city: City) = dao.insert(city)
41
42 suspend fun updateCity(city: City) = dao.update(city)
43
44 suspend fun deleteCity(city: City) = dao.delete(city)
45
46 suspend fun getCityById(id: Int) = dao.getCityById(id)
47
48}
49@Database(entities = [City::class], version = 2, exportSchema = false)
50abstract class AppDatabase : RoomDatabase() {
51 abstract fun getCityDao() : CityDao
52}
53@Composable
54fun HomeScreen(
55 navigateToDetailsAction: () -> Unit,
56 openCardDetailsAction: (Int) -> Unit
57) {
58 val viewModel: HomeViewModel = hiltViewModel()
59 val cities = viewModel.cities.observeAsState(listOf())
60 Scaffold(
61 topBar = { HomeAppBar() },
62 floatingActionButton = { HomeFab(navigateToDetailsAction) }
63 ) {
64 HomeContent(cities) { id -> openCardDetailsAction(id) }
65 }
66}
67@Preview
68@Composable
69private fun HomeScreenPreview() {
70 val viewModel = HomeViewModel()
71 // setup viewModel as you need it to be in the preview
72 HomeScreen(viewModel = viewModel, navigateToDetailsAction = {}, openCardDetailsAction = {})
73}
74interface CityRepositoryI {
75 val allCities: List<City>
76
77 suspend fun addCity(city: City)
78 suspend fun updateCity(city: City)
79 suspend fun deleteCity(city: City)
80 suspend fun getCityById(id: Int)
81}
82@ViewModelScoped
83class CityRepository @Inject constructor(appDatabase: AppDatabase) : CityRepositoryI {
84 private val dao by lazy { appDatabase.getCityDao() }
85
86 override val allCities by lazy { dao.getAllCities() }
87
88 override suspend fun addCity(city: City) = dao.insert(city)
89
90 override suspend fun updateCity(city: City) = dao.update(city)
91
92 override suspend fun deleteCity(city: City) = dao.delete(city)
93
94 override suspend fun getCityById(id: Int) = dao.getCityById(id)
95}
96
- Create
FakeCityRepository
for testing purposes:
1java.lang.IllegalStateException: ViewModels creation is not supported in Preview
2 at androidx.compose.ui.tooling.ComposeViewAdapter$FakeViewModelStoreOwner$1.getViewModelStore(ComposeViewAdapter.kt:709)
3 at androidx.lifecycle.ViewModelProvider.<init>(ViewModelProvider.kt:105)
4 at androidx.lifecycle.viewmodel.compose.ViewModelKt.get(ViewModel.kt:82)
5 at androidx.lifecycle.viewmodel.compose.ViewModelKt.viewModel(ViewModel.kt:72)
6 at com.example.crud.ui.screens.home.HomeScreenKt.HomeScreen(HomeScreen.kt:53)
7 at com.example.crud.ui.screens.home.HomeScreenKt.HomeScreenPreview(HomeScreen.kt:43)
8 at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
9 at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
10 ...
11@Composable
12fun HomeScreen(
13 viewModel: HomeViewModel = hiltViewModel(),
14 navigateToDetailsAction: () -> Unit,
15 openCardDetailsAction: (Int) -> Unit
16) {
17 val cities = viewModel.cities.observeAsState(listOf())
18 Scaffold(
19 topBar = { HomeAppBar() },
20 floatingActionButton = { HomeFab(navigateToDetailsAction) }
21 ) {
22 HomeContent(cities) { id -> openCardDetailsAction(id) }
23 }
24}
25@Preview
26@Composable
27private fun HomeScreenPreview() {
28 HomeScreen(navigateToDetailsAction = {}, openCardDetailsAction = {})
29}
30@HiltViewModel
31class HomeViewModel @Inject constructor(repository: CityRepository) : ViewModel() {
32 val cities: LiveData<List<City>> = repository.allCities.asLiveData()
33}
34@ViewModelScoped
35class CityRepository @Inject constructor(appDatabase: AppDatabase) {
36 private val dao by lazy { appDatabase.getCityDao() }
37
38 val allCities by lazy { dao.getAllCities() }
39
40 suspend fun addCity(city: City) = dao.insert(city)
41
42 suspend fun updateCity(city: City) = dao.update(city)
43
44 suspend fun deleteCity(city: City) = dao.delete(city)
45
46 suspend fun getCityById(id: Int) = dao.getCityById(id)
47
48}
49@Database(entities = [City::class], version = 2, exportSchema = false)
50abstract class AppDatabase : RoomDatabase() {
51 abstract fun getCityDao() : CityDao
52}
53@Composable
54fun HomeScreen(
55 navigateToDetailsAction: () -> Unit,
56 openCardDetailsAction: (Int) -> Unit
57) {
58 val viewModel: HomeViewModel = hiltViewModel()
59 val cities = viewModel.cities.observeAsState(listOf())
60 Scaffold(
61 topBar = { HomeAppBar() },
62 floatingActionButton = { HomeFab(navigateToDetailsAction) }
63 ) {
64 HomeContent(cities) { id -> openCardDetailsAction(id) }
65 }
66}
67@Preview
68@Composable
69private fun HomeScreenPreview() {
70 val viewModel = HomeViewModel()
71 // setup viewModel as you need it to be in the preview
72 HomeScreen(viewModel = viewModel, navigateToDetailsAction = {}, openCardDetailsAction = {})
73}
74interface CityRepositoryI {
75 val allCities: List<City>
76
77 suspend fun addCity(city: City)
78 suspend fun updateCity(city: City)
79 suspend fun deleteCity(city: City)
80 suspend fun getCityById(id: Int)
81}
82@ViewModelScoped
83class CityRepository @Inject constructor(appDatabase: AppDatabase) : CityRepositoryI {
84 private val dao by lazy { appDatabase.getCityDao() }
85
86 override val allCities by lazy { dao.getAllCities() }
87
88 override suspend fun addCity(city: City) = dao.insert(city)
89
90 override suspend fun updateCity(city: City) = dao.update(city)
91
92 override suspend fun deleteCity(city: City) = dao.delete(city)
93
94 override suspend fun getCityById(id: Int) = dao.getCityById(id)
95}
96class FakeCityRepository : CityRepositoryI {
97 // predefined cities for testing
98 val cities = listOf(
99 City(1)
100 ).toMutableStateList()
101
102 override val allCities by lazy { cities }
103
104 override suspend fun addCity(city: City) {
105 cities.add(city)
106 }
107
108 override suspend fun updateCity(city: City){
109 val index = cities.indexOfFirst { it.id == city.id }
110 cities[index] = city
111 }
112
113 override suspend fun deleteCity(city: City) {
114 cities.removeAll { it.id == city.id }
115 }
116
117 override suspend fun getCityById(id: Int) = cities.first { it.id == id }
118}
119
So you can pass it into your view model: HomeViewModel(FakeCityRepository())
You can do the same with AppDatabase
instead of a repository, it all depends on your needs. Check out more about Hilt testing
p.s. I'm not sure if this will build, since I don't have some of your classes, but you should have caught the idea.
QUESTION
v0.8 AggregatorV3Interface.sol , its available in @chainlink/contracts?
Asked 2021-Nov-05 at 21:48I get a error when i change the version to 0.8 , but works fine with 0.6, how i see the most recent version? , i tried downloaded from npm install @chainlink/contracts --save, but only works with mock mode.
This is my repo: https://github.com/irwingtello/lottery
Compiling contracts... Solc version: 0.8.9 Optimizer: Enabled Runs: 200 EVM Version: Istanbul CompilerError: solc returned the following errors:
ParserError: Source "C:/Users/irwin/.brownie/packages/smartcontractkit/chainlink-brownie-contracts@1.1.1/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol" not found: File not found. --> contracts/Lottery.sol:4:1: | 4 | import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ERROR: Unable to load project
ANSWER
Answered 2021-Nov-05 at 21:48"As of 1.2.0 and onward all the releases of this package are going to match the @chainlink/contracts
NPM tags
So it will look backwards
, but we are starting with 0.2.1
"
Change: @chainlink=smartcontractkit/chainlink-brownie-contracts@1.1.1
To: @chainlink=smartcontractkit/chainlink-brownie-contracts@0.2.1
https://github.com/smartcontractkit/chainlink-brownie-contracts/tree/v0.2.1
QUESTION
Not able to mock a function inside useEffect
Asked 2021-Oct-13 at 08:26I have a custom hook as below
1export const useUserSearch = () => {
2 const [options, setOptions] = useState([]);
3 const [searchString, setSearchString] = useState("");
4 const [userSearch] = useUserSearchMutation();
5 useEffect(() => {
6 if (searchString.trim().length > 3) {
7 const searchParams = {
8 orgId: "1",
9 userId: "1",
10 searchQuery: searchString.trim(),
11 };
12 userSearch(searchParams)
13 .then((data) => {
14 setOptions(data);
15 })
16 .catch((err) => {
17 setOptions([]);
18 console.log("error", err);
19 });
20 }
21 }, [searchString, userSearch]);
22 return {
23 options,
24 setSearchString,
25 };
26};
27
and I want to test this hook but am not able to mock userSearch
function which is being called inside useEffect.
can anybody help?
this is my test
1export const useUserSearch = () => {
2 const [options, setOptions] = useState([]);
3 const [searchString, setSearchString] = useState("");
4 const [userSearch] = useUserSearchMutation();
5 useEffect(() => {
6 if (searchString.trim().length > 3) {
7 const searchParams = {
8 orgId: "1",
9 userId: "1",
10 searchQuery: searchString.trim(),
11 };
12 userSearch(searchParams)
13 .then((data) => {
14 setOptions(data);
15 })
16 .catch((err) => {
17 setOptions([]);
18 console.log("error", err);
19 });
20 }
21 }, [searchString, userSearch]);
22 return {
23 options,
24 setSearchString,
25 };
26};
27it('should set state and test function', async () => {
28 const wrapper = ({ children }) => (
29 <Provider store={store}>{children}</Provider>
30 )
31 const { result } = renderHook(
32 () => useUserSearch(),
33 { wrapper }
34 )
35 await act(async () => {
36 result.current.setSearchString('abc5')
37 })
38 expect(result.current.options).toEqual(expected)
39})
40
useUserSearchMutation
1export const useUserSearch = () => {
2 const [options, setOptions] = useState([]);
3 const [searchString, setSearchString] = useState("");
4 const [userSearch] = useUserSearchMutation();
5 useEffect(() => {
6 if (searchString.trim().length > 3) {
7 const searchParams = {
8 orgId: "1",
9 userId: "1",
10 searchQuery: searchString.trim(),
11 };
12 userSearch(searchParams)
13 .then((data) => {
14 setOptions(data);
15 })
16 .catch((err) => {
17 setOptions([]);
18 console.log("error", err);
19 });
20 }
21 }, [searchString, userSearch]);
22 return {
23 options,
24 setSearchString,
25 };
26};
27it('should set state and test function', async () => {
28 const wrapper = ({ children }) => (
29 <Provider store={store}>{children}</Provider>
30 )
31 const { result } = renderHook(
32 () => useUserSearch(),
33 { wrapper }
34 )
35 await act(async () => {
36 result.current.setSearchString('abc5')
37 })
38 expect(result.current.options).toEqual(expected)
39})
40import {createApi, fetchBaseQuery} from '@reduxjs/toolkit/query/react';
41export const userSearchAPI = createApi({
42 reducerPath: 'userSearchResult',
43 baseQuery: fetchBaseQuery({baseUrl: process.env.REACT_APP_BASE_URL}),
44 tagTypes: ['Users'],
45 endpoints: build => ({
46 userSearch: build.mutation({
47 query: body => ({url: '/org/patient/search', method: 'POST', body}),
48 invalidatesTags: ['Users'],
49 }),
50 }),
51});
52export const {useUserSearchMutation} = userSearchAPI;
53
ANSWER
Answered 2021-Oct-13 at 05:27Because it's a named export you should return an object in the mock
1export const useUserSearch = () => {
2 const [options, setOptions] = useState([]);
3 const [searchString, setSearchString] = useState("");
4 const [userSearch] = useUserSearchMutation();
5 useEffect(() => {
6 if (searchString.trim().length > 3) {
7 const searchParams = {
8 orgId: "1",
9 userId: "1",
10 searchQuery: searchString.trim(),
11 };
12 userSearch(searchParams)
13 .then((data) => {
14 setOptions(data);
15 })
16 .catch((err) => {
17 setOptions([]);
18 console.log("error", err);
19 });
20 }
21 }, [searchString, userSearch]);
22 return {
23 options,
24 setSearchString,
25 };
26};
27it('should set state and test function', async () => {
28 const wrapper = ({ children }) => (
29 <Provider store={store}>{children}</Provider>
30 )
31 const { result } = renderHook(
32 () => useUserSearch(),
33 { wrapper }
34 )
35 await act(async () => {
36 result.current.setSearchString('abc5')
37 })
38 expect(result.current.options).toEqual(expected)
39})
40import {createApi, fetchBaseQuery} from '@reduxjs/toolkit/query/react';
41export const userSearchAPI = createApi({
42 reducerPath: 'userSearchResult',
43 baseQuery: fetchBaseQuery({baseUrl: process.env.REACT_APP_BASE_URL}),
44 tagTypes: ['Users'],
45 endpoints: build => ({
46 userSearch: build.mutation({
47 query: body => ({url: '/org/patient/search', method: 'POST', body}),
48 invalidatesTags: ['Users'],
49 }),
50 }),
51});
52export const {useUserSearchMutation} = userSearchAPI;
53it("should set state and test function", async () => {
54 jest.mock("./useUserSearchMutation", () => ({
55 useUserSearchMutation: () => [jest.fn().mockResolvedValue(expected)],
56 }));
57 const wrapper = ({ children }) => (
58...
59});
60
QUESTION
pytest/unittest: mock.patch function from module?
Asked 2021-Sep-22 at 07:06Given a folder structure like such:
1dags/
2 **/
3 code.py
4tests/
5 dags/
6 **/
7 test_code.py
8 conftest.py
9
Where dags serves as the root of the src files, with 'dags/a/b/c.py' imported as 'a.b.c'.
I want to test the following function in code.py:
1dags/
2 **/
3 code.py
4tests/
5 dags/
6 **/
7 test_code.py
8 conftest.py
9from dag_common.connections import get_conn
10from utils.database import dbtypes
11
12def select_records(
13 conn_id: str,
14 sql: str,
15 bindings,
16):
17 conn: dbtypes.Connection = get_conn(conn_id)
18 with conn.cursor() as cursor:
19 cursor.execute(
20 sql, bindings
21 )
22 records = cursor.fetchall()
23 return records
24
But I am faced with the issue that I fail to find a way to patch the get_conn
from dag_common.connections
. I attempted the following:
1dags/
2 **/
3 code.py
4tests/
5 dags/
6 **/
7 test_code.py
8 conftest.py
9from dag_common.connections import get_conn
10from utils.database import dbtypes
11
12def select_records(
13 conn_id: str,
14 sql: str,
15 bindings,
16):
17 conn: dbtypes.Connection = get_conn(conn_id)
18 with conn.cursor() as cursor:
19 cursor.execute(
20 sql, bindings
21 )
22 records = cursor.fetchall()
23 return records
24import os
25import sys
26
27# adds dags to sys.path for tests/*.py files to be able to import them
28sys.path.append(os.path.join(os.path.dirname(__file__), "..", "dags"))
29
30{{fixtures}}
31
Where I have tested the following replacements for {{fixtures}}
:
(1.a) - default
1dags/
2 **/
3 code.py
4tests/
5 dags/
6 **/
7 test_code.py
8 conftest.py
9from dag_common.connections import get_conn
10from utils.database import dbtypes
11
12def select_records(
13 conn_id: str,
14 sql: str,
15 bindings,
16):
17 conn: dbtypes.Connection = get_conn(conn_id)
18 with conn.cursor() as cursor:
19 cursor.execute(
20 sql, bindings
21 )
22 records = cursor.fetchall()
23 return records
24import os
25import sys
26
27# adds dags to sys.path for tests/*.py files to be able to import them
28sys.path.append(os.path.join(os.path.dirname(__file__), "..", "dags"))
29
30{{fixtures}}
31@pytest.fixture(autouse=True, scope="function")
32def mock_get_conn():
33 with mock.patch("dag_common.connections.get_conn") as mock_getter:
34 yield mock_getter
35
(1.b) - prefixing path with dags
1dags/
2 **/
3 code.py
4tests/
5 dags/
6 **/
7 test_code.py
8 conftest.py
9from dag_common.connections import get_conn
10from utils.database import dbtypes
11
12def select_records(
13 conn_id: str,
14 sql: str,
15 bindings,
16):
17 conn: dbtypes.Connection = get_conn(conn_id)
18 with conn.cursor() as cursor:
19 cursor.execute(
20 sql, bindings
21 )
22 records = cursor.fetchall()
23 return records
24import os
25import sys
26
27# adds dags to sys.path for tests/*.py files to be able to import them
28sys.path.append(os.path.join(os.path.dirname(__file__), "..", "dags"))
29
30{{fixtures}}
31@pytest.fixture(autouse=True, scope="function")
32def mock_get_conn():
33 with mock.patch("dag_common.connections.get_conn") as mock_getter:
34 yield mock_getter
35@pytest.fixture(autouse=True, scope="function")
36def mock_get_conn():
37 with mock.patch("dags.dag_common.connections.get_conn") as mock_getter:
38 yield mock_getter
39
(1.c) - 1.a, with scope="session"
(1.d) - 1.b, with scope="session"
(1.e) - object patching the module itself
1dags/
2 **/
3 code.py
4tests/
5 dags/
6 **/
7 test_code.py
8 conftest.py
9from dag_common.connections import get_conn
10from utils.database import dbtypes
11
12def select_records(
13 conn_id: str,
14 sql: str,
15 bindings,
16):
17 conn: dbtypes.Connection = get_conn(conn_id)
18 with conn.cursor() as cursor:
19 cursor.execute(
20 sql, bindings
21 )
22 records = cursor.fetchall()
23 return records
24import os
25import sys
26
27# adds dags to sys.path for tests/*.py files to be able to import them
28sys.path.append(os.path.join(os.path.dirname(__file__), "..", "dags"))
29
30{{fixtures}}
31@pytest.fixture(autouse=True, scope="function")
32def mock_get_conn():
33 with mock.patch("dag_common.connections.get_conn") as mock_getter:
34 yield mock_getter
35@pytest.fixture(autouse=True, scope="function")
36def mock_get_conn():
37 with mock.patch("dags.dag_common.connections.get_conn") as mock_getter:
38 yield mock_getter
39@pytest.fixture(autouse=True, scope="function")
40def mock_get_conn():
41 import dags.dag_common.connections
42 mock_getter = mock.MagicMock()
43 with mock.patch.object(dags.dag_common.connections, 'get_conn', mock_getter):
44 yield mock_getter
45
(1.f) - 1.a, but using pytest-mock fixture
1dags/
2 **/
3 code.py
4tests/
5 dags/
6 **/
7 test_code.py
8 conftest.py
9from dag_common.connections import get_conn
10from utils.database import dbtypes
11
12def select_records(
13 conn_id: str,
14 sql: str,
15 bindings,
16):
17 conn: dbtypes.Connection = get_conn(conn_id)
18 with conn.cursor() as cursor:
19 cursor.execute(
20 sql, bindings
21 )
22 records = cursor.fetchall()
23 return records
24import os
25import sys
26
27# adds dags to sys.path for tests/*.py files to be able to import them
28sys.path.append(os.path.join(os.path.dirname(__file__), "..", "dags"))
29
30{{fixtures}}
31@pytest.fixture(autouse=True, scope="function")
32def mock_get_conn():
33 with mock.patch("dag_common.connections.get_conn") as mock_getter:
34 yield mock_getter
35@pytest.fixture(autouse=True, scope="function")
36def mock_get_conn():
37 with mock.patch("dags.dag_common.connections.get_conn") as mock_getter:
38 yield mock_getter
39@pytest.fixture(autouse=True, scope="function")
40def mock_get_conn():
41 import dags.dag_common.connections
42 mock_getter = mock.MagicMock()
43 with mock.patch.object(dags.dag_common.connections, 'get_conn', mock_getter):
44 yield mock_getter
45@pytest.fixture(autouse=True, scope="function")
46def mock_get_conn(mocker):
47 with mocker.patch("dag_common.connections.get_conn") as mock_getter:
48 yield mock_getter
49
(1.g) - 1.b, but using pytest-mock fixture
(1.h) - 1.a, but using pytest's monkeypatch
1dags/
2 **/
3 code.py
4tests/
5 dags/
6 **/
7 test_code.py
8 conftest.py
9from dag_common.connections import get_conn
10from utils.database import dbtypes
11
12def select_records(
13 conn_id: str,
14 sql: str,
15 bindings,
16):
17 conn: dbtypes.Connection = get_conn(conn_id)
18 with conn.cursor() as cursor:
19 cursor.execute(
20 sql, bindings
21 )
22 records = cursor.fetchall()
23 return records
24import os
25import sys
26
27# adds dags to sys.path for tests/*.py files to be able to import them
28sys.path.append(os.path.join(os.path.dirname(__file__), "..", "dags"))
29
30{{fixtures}}
31@pytest.fixture(autouse=True, scope="function")
32def mock_get_conn():
33 with mock.patch("dag_common.connections.get_conn") as mock_getter:
34 yield mock_getter
35@pytest.fixture(autouse=True, scope="function")
36def mock_get_conn():
37 with mock.patch("dags.dag_common.connections.get_conn") as mock_getter:
38 yield mock_getter
39@pytest.fixture(autouse=True, scope="function")
40def mock_get_conn():
41 import dags.dag_common.connections
42 mock_getter = mock.MagicMock()
43 with mock.patch.object(dags.dag_common.connections, 'get_conn', mock_getter):
44 yield mock_getter
45@pytest.fixture(autouse=True, scope="function")
46def mock_get_conn(mocker):
47 with mocker.patch("dag_common.connections.get_conn") as mock_getter:
48 yield mock_getter
49@pytest.fixture(autouse=True, scope="function")
50def mock_get_conn(mocker, monkeypatch):
51 import dags.dag_common.connections
52 mock_getter = mocker.MagicMock()
53 monkeypatch.setattr(dags.dag_common.connections, 'get_conn', mock_getter)
54 yield mock_getter
55
(2.a) - decorator @mock.patch("dag_common.connections.get_conn")
1dags/
2 **/
3 code.py
4tests/
5 dags/
6 **/
7 test_code.py
8 conftest.py
9from dag_common.connections import get_conn
10from utils.database import dbtypes
11
12def select_records(
13 conn_id: str,
14 sql: str,
15 bindings,
16):
17 conn: dbtypes.Connection = get_conn(conn_id)
18 with conn.cursor() as cursor:
19 cursor.execute(
20 sql, bindings
21 )
22 records = cursor.fetchall()
23 return records
24import os
25import sys
26
27# adds dags to sys.path for tests/*.py files to be able to import them
28sys.path.append(os.path.join(os.path.dirname(__file__), "..", "dags"))
29
30{{fixtures}}
31@pytest.fixture(autouse=True, scope="function")
32def mock_get_conn():
33 with mock.patch("dag_common.connections.get_conn") as mock_getter:
34 yield mock_getter
35@pytest.fixture(autouse=True, scope="function")
36def mock_get_conn():
37 with mock.patch("dags.dag_common.connections.get_conn") as mock_getter:
38 yield mock_getter
39@pytest.fixture(autouse=True, scope="function")
40def mock_get_conn():
41 import dags.dag_common.connections
42 mock_getter = mock.MagicMock()
43 with mock.patch.object(dags.dag_common.connections, 'get_conn', mock_getter):
44 yield mock_getter
45@pytest.fixture(autouse=True, scope="function")
46def mock_get_conn(mocker):
47 with mocker.patch("dag_common.connections.get_conn") as mock_getter:
48 yield mock_getter
49@pytest.fixture(autouse=True, scope="function")
50def mock_get_conn(mocker, monkeypatch):
51 import dags.dag_common.connections
52 mock_getter = mocker.MagicMock()
53 monkeypatch.setattr(dags.dag_common.connections, 'get_conn', mock_getter)
54 yield mock_getter
55 @mock.patch("dag_common.connections.get_conn")
56 def test_executes_sql_with_default_bindings(mock_getter, mock_context):
57 # arrange
58 sql = "SELECT * FROM table"
59 records = [RealDictRow(col1=1), RealDictRow(col1=2)]
60 mock_conn = mock_getter.return_value
61 mock_cursor = mock_conn.cursor.return_value
62 mock_cursor.execute.return_value = records
63 # act
64 select_records(conn_id="orca", sql=sql, ) # ...
65 # assert
66 mock_cursor.execute.assert_called_once_with(
67 sql, # ...
68 )
69
(2.b) - (2.a) but with "dags." prefix
(2.c) - context manager
1dags/
2 **/
3 code.py
4tests/
5 dags/
6 **/
7 test_code.py
8 conftest.py
9from dag_common.connections import get_conn
10from utils.database import dbtypes
11
12def select_records(
13 conn_id: str,
14 sql: str,
15 bindings,
16):
17 conn: dbtypes.Connection = get_conn(conn_id)
18 with conn.cursor() as cursor:
19 cursor.execute(
20 sql, bindings
21 )
22 records = cursor.fetchall()
23 return records
24import os
25import sys
26
27# adds dags to sys.path for tests/*.py files to be able to import them
28sys.path.append(os.path.join(os.path.dirname(__file__), "..", "dags"))
29
30{{fixtures}}
31@pytest.fixture(autouse=True, scope="function")
32def mock_get_conn():
33 with mock.patch("dag_common.connections.get_conn") as mock_getter:
34 yield mock_getter
35@pytest.fixture(autouse=True, scope="function")
36def mock_get_conn():
37 with mock.patch("dags.dag_common.connections.get_conn") as mock_getter:
38 yield mock_getter
39@pytest.fixture(autouse=True, scope="function")
40def mock_get_conn():
41 import dags.dag_common.connections
42 mock_getter = mock.MagicMock()
43 with mock.patch.object(dags.dag_common.connections, 'get_conn', mock_getter):
44 yield mock_getter
45@pytest.fixture(autouse=True, scope="function")
46def mock_get_conn(mocker):
47 with mocker.patch("dag_common.connections.get_conn") as mock_getter:
48 yield mock_getter
49@pytest.fixture(autouse=True, scope="function")
50def mock_get_conn(mocker, monkeypatch):
51 import dags.dag_common.connections
52 mock_getter = mocker.MagicMock()
53 monkeypatch.setattr(dags.dag_common.connections, 'get_conn', mock_getter)
54 yield mock_getter
55 @mock.patch("dag_common.connections.get_conn")
56 def test_executes_sql_with_default_bindings(mock_getter, mock_context):
57 # arrange
58 sql = "SELECT * FROM table"
59 records = [RealDictRow(col1=1), RealDictRow(col1=2)]
60 mock_conn = mock_getter.return_value
61 mock_cursor = mock_conn.cursor.return_value
62 mock_cursor.execute.return_value = records
63 # act
64 select_records(conn_id="orca", sql=sql, ) # ...
65 # assert
66 mock_cursor.execute.assert_called_once_with(
67 sql, # ...
68 )
69 def test_executes_sql_with_default_bindings(mock_context):
70 # arrange
71 sql = "SELECT * FROM table"
72 records = [RealDictRow(col1=1), RealDictRow(col1=2)]
73 with mock.patch("dag_common.connections.get_conn") as mock_getter:
74 mock_conn = mock_getter.return_value
75 mock_cursor = mock_conn.cursor.return_value
76 mock_cursor.execute.return_value = records
77 # act
78 select_records(conn_id="orca", sql=sql, ) # ...
79 # assert
80 mock_cursor.execute.assert_called_once_with(
81 sql, # ...
82 )
83
(2.d) - (2.c) but with "dags." prefix
Conclusion
But alas, no matter what solution I pick, the function-to-be-mocked still gets called. I made sure to attempt each solution separatedly from each other, and to kill/clear/restart my pytest-watch process in between attempts.
I feel like this may be related to me meddling with sys.path in conftest.py, because outside of this I feel like I have exhausted all possibilities.
Any idea how I can solve this?
ANSWER
Answered 2021-Sep-22 at 07:06Yeah. I also fought with this initially when I learned patching and mocking and know how frustrating it is as you seem to be doing everything right, but it does not work. I sympathise with you!
This is actually how mocking of imported stuff works, and once you realise it, it actually makes sense.
The problem is that import works in the way that it makes the imported module available in the context of where your import is.
Lets' assume your code.py
module is in 'my_package' folder. Your code is available then as my_package.code
. And once you use from dag_common.connections import get_conn
in code
module - the imported get_conn
becomes available as .... my_package.code.get_conn
And in this case you need to patch my_package.code.get_conn
not the original package you imported get_conn from.
Once you realise this, patching becomes much easier.
Community Discussions contain sources that include Stack Exchange Network
Tutorials and Learning Resources in Mock
Tutorials and Learning Resources are not available at this moment for Mock