Compare commits

..

1 Commits

Author SHA1 Message Date
forgetest5 3147e7ac9d ADD file via upload 2021-08-05 13:20:45 +08:00
409 changed files with 173 additions and 122822 deletions

View File

@ -1,174 +0,0 @@
{
"TechnicianId": 161555,
"AffiliateId": 0,
"ScheduleStartTime": "2019-07-25T08:00:00",
"ScheduleEndTime": "2019-07-25T12:00:00",
"WorkOrders": [{
"Id": 2035478,
"StartTime": "2019-07-24T10:00:00",
"EndTime": "2019-07-24T11:22:39",
"ScheduleStartTime": "2019-07-24T10:00:00",
"ScheduleEndTime": "2019-07-24T14:00:00",
"Technician": 161555,
"WOClientId": 1200,
"AffiliateId": 116531,
"WoTypeId": 70,
"ProjectId": 8637,
"IsLockedTechnician": false,
"Section": 2,
"OnSiteTime": 3600,
"PriorityId": 0,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 0,
"ServiceCodeId": 8164,
"ServiceTypeId": 1637,
"ServiceCategoryId": 96,
"IsScheduleAtRisk": false,
"IsDetach": false,
"LocationId": 808648,
"UTC": 0,
"DST": null,
"ConvertZipCode": true,
"Lat": 36.09564,
"Lng": -80.7957,
"ZipCode": "27020",
"State": "NC",
"Region": "Carolinas"
},
{
"Id": 2035476,
"StartTime": "2019-07-24T11:22:39",
"EndTime": "2019-07-24T13:10:38",
"ScheduleStartTime": "2019-07-24T10:00:00",
"ScheduleEndTime": "2019-07-24T14:00:00",
"Technician": 161555,
"WOClientId": 1200,
"AffiliateId": 116531,
"WoTypeId": 70,
"ProjectId": 8636,
"IsLockedTechnician": false,
"Section": 2,
"OnSiteTime": 3600,
"PriorityId": 0,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 0,
"ServiceCodeId": 8164,
"ServiceTypeId": 1637,
"ServiceCategoryId": 96,
"IsScheduleAtRisk": false,
"IsDetach": false,
"LocationId": 808646,
"UTC": 0,
"DST": null,
"ConvertZipCode": true,
"Lat": 35.575801,
"Lng": -80.819083,
"ZipCode": "28115",
"State": "NC",
"Region": "Carolinas"
},
{
"Id": 2035670,
"StartTime": "2019-07-24T11:22:39",
"EndTime": "2019-07-24T13:10:38",
"ScheduleStartTime": "2019-07-24T10:00:00",
"ScheduleEndTime": "2019-07-24T14:00:00",
"Technician": 161555,
"WOClientId": 1200,
"AffiliateId": 116531,
"WoTypeId": 30,
"ProjectId": 0,
"IsLockedTechnician": false,
"Section": 2,
"OnSiteTime": 3600,
"PriorityId": 0,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 0,
"ServiceCodeId": 5316,
"ServiceTypeId": 1248,
"ServiceCategoryId": 1,
"IsScheduleAtRisk": true,
"IsDetach": false,
"LocationId": 808646,
"UTC": 0,
"DST": null,
"ConvertZipCode": true,
"Lat": 35.575801,
"Lng": -80.819083,
"ZipCode": "28115",
"State": "NC",
"Region": "Carolinas"
},
{
"Id": 2036049,
"StartTime": "2019-07-25T08:00:00",
"EndTime": "2019-07-25T09:58:38",
"ScheduleStartTime": "2019-07-25T08:00:00",
"ScheduleEndTime": "2019-07-25T12:00:00",
"Technician": 161555,
"WOClientId": 1200,
"AffiliateId": 116531,
"WoTypeId": 70,
"ProjectId": 8652,
"IsLockedTechnician": false,
"Section": 1,
"OnSiteTime": 3600,
"PriorityId": 0,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 0,
"ServiceCodeId": 8164,
"ServiceTypeId": 1637,
"ServiceCategoryId": 96,
"IsScheduleAtRisk": false,
"IsDetach": false,
"LocationId": 808651,
"UTC": 0,
"DST": null,
"ConvertZipCode": true,
"Lat": 35.483897,
"Lng": -80.599575,
"ZipCode": "28083",
"State": "NC",
"Region": "Carolinas"
},
{
"Id": 0,
"StartTime": "2019-07-25T08:00:00",
"EndTime": "2019-07-25T09:58:38",
"ScheduleStartTime": "2019-07-25T08:00:00",
"ScheduleEndTime": "2019-07-25T12:00:00",
"Technician": 0,
"WOClientId": 1200,
"AffiliateId": 0,
"WoTypeId": 0,
"ProjectId": 8652,
"IsLockedTechnician": false,
"Section": 0,
"OnSiteTime": 3600,
"PriorityId": 9,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 1,
"ServiceCodeId": 8164,
"ServiceTypeId": 1637,
"ServiceCategoryId": 8164,
"IsScheduleAtRisk": false,
"IsDetach": false,
"LocationId": 808651,
"UTC": 0,
"DST": null,
"ConvertZipCode": false,
"Lat": 35.483897,
"Lng": -80.599575,
"ZipCode": "28083",
"State": null,
"Region": null
}
],
"IsSchedule": false,
"OnSiteTime": 0,
"IncrementSecond": 0,
"TotalDrivingTime": 9090,
"AtRiskWoIds": [
2035670
]
}

View File

@ -1,174 +0,0 @@
{
"TechnicianId": 161555,
"AffiliateId": 0,
"ScheduleStartTime": "2019-07-25T08:00:00",
"ScheduleEndTime": "2019-07-25T12:00:00",
"WorkOrders": [{
"Id": 2035478,
"StartTime": "2019-07-24T10:00:00",
"EndTime": "2019-07-24T11:22:39",
"ScheduleStartTime": "2019-07-24T10:00:00",
"ScheduleEndTime": "2019-07-24T14:00:00",
"Technician": 161555,
"WOClientId": 1200,
"AffiliateId": 116531,
"WoTypeId": 70,
"ProjectId": 8637,
"IsLockedTechnician": false,
"Section": 2,
"OnSiteTime": 3600,
"PriorityId": 0,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 0,
"ServiceCodeId": 8164,
"ServiceTypeId": 1637,
"ServiceCategoryId": 96,
"IsScheduleAtRisk": false,
"IsDetach": false,
"LocationId": 808648,
"UTC": 0,
"DST": null,
"ConvertZipCode": true,
"Lat": 36.09564,
"Lng": -80.7957,
"ZipCode": "27020",
"State": "NC",
"Region": "Carolinas"
},
{
"Id": 2035476,
"StartTime": "2019-07-24T11:22:39",
"EndTime": "2019-07-24T13:10:38",
"ScheduleStartTime": "2019-07-24T10:00:00",
"ScheduleEndTime": "2019-07-24T14:00:00",
"Technician": 161555,
"WOClientId": 1200,
"AffiliateId": 116531,
"WoTypeId": 70,
"ProjectId": 8636,
"IsLockedTechnician": false,
"Section": 2,
"OnSiteTime": 3600,
"PriorityId": 0,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 0,
"ServiceCodeId": 8164,
"ServiceTypeId": 1637,
"ServiceCategoryId": 96,
"IsScheduleAtRisk": false,
"IsDetach": false,
"LocationId": 808646,
"UTC": 0,
"DST": null,
"ConvertZipCode": true,
"Lat": 35.575801,
"Lng": -80.819083,
"ZipCode": "28115",
"State": "NC",
"Region": "Carolinas"
},
{
"Id": 2035670,
"StartTime": "2019-07-24T11:22:39",
"EndTime": "2019-07-24T13:10:38",
"ScheduleStartTime": "2019-07-24T10:00:00",
"ScheduleEndTime": "2019-07-24T14:00:00",
"Technician": 161555,
"WOClientId": 1200,
"AffiliateId": 116531,
"WoTypeId": 30,
"ProjectId": 0,
"IsLockedTechnician": false,
"Section": 2,
"OnSiteTime": 3600,
"PriorityId": 0,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 0,
"ServiceCodeId": 5316,
"ServiceTypeId": 1248,
"ServiceCategoryId": 1,
"IsScheduleAtRisk": true,
"IsDetach": false,
"LocationId": 808646,
"UTC": 0,
"DST": null,
"ConvertZipCode": true,
"Lat": 35.575801,
"Lng": -80.819083,
"ZipCode": "28115",
"State": "NC",
"Region": "Carolinas"
},
{
"Id": 2036049,
"StartTime": "2019-07-25T08:00:00",
"EndTime": "2019-07-25T09:58:38",
"ScheduleStartTime": "2019-07-25T08:00:00",
"ScheduleEndTime": "2019-07-25T12:00:00",
"Technician": 161555,
"WOClientId": 1200,
"AffiliateId": 116531,
"WoTypeId": 70,
"ProjectId": 8652,
"IsLockedTechnician": false,
"Section": 1,
"OnSiteTime": 3600,
"PriorityId": 0,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 0,
"ServiceCodeId": 8164,
"ServiceTypeId": 1637,
"ServiceCategoryId": 96,
"IsScheduleAtRisk": false,
"IsDetach": false,
"LocationId": 808651,
"UTC": 0,
"DST": null,
"ConvertZipCode": true,
"Lat": 35.483897,
"Lng": -80.599575,
"ZipCode": "28083",
"State": "NC",
"Region": "Carolinas"
},
{
"Id": 0,
"StartTime": "2019-07-25T08:00:00",
"EndTime": "2019-07-25T09:58:38",
"ScheduleStartTime": "2019-07-25T08:00:00",
"ScheduleEndTime": "2019-07-25T12:00:00",
"Technician": 0,
"WOClientId": 1200,
"AffiliateId": 0,
"WoTypeId": 0,
"ProjectId": 8652,
"IsLockedTechnician": false,
"Section": 0,
"OnSiteTime": 3600,
"PriorityId": 9,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 1,
"ServiceCodeId": 8164,
"ServiceTypeId": 1637,
"ServiceCategoryId": 8164,
"IsScheduleAtRisk": false,
"IsDetach": false,
"LocationId": 808651,
"UTC": 0,
"DST": null,
"ConvertZipCode": false,
"Lat": 35.483897,
"Lng": -80.599575,
"ZipCode": "28083",
"State": null,
"Region": null
}
],
"IsSchedule": false,
"OnSiteTime": 0,
"IncrementSecond": 0,
"TotalDrivingTime": 9090,
"AtRiskWoIds": [
2035670
]
}

View File

@ -1,174 +0,0 @@
{
"TechnicianId": 161555,
"AffiliateId": 0,
"ScheduleStartTime": "2019-07-25T08:00:00",
"ScheduleEndTime": "2019-07-25T12:00:00",
"WorkOrders": [{
"Id": 2035478,
"StartTime": "2019-07-24T10:00:00",
"EndTime": "2019-07-24T11:22:39",
"ScheduleStartTime": "2019-07-24T10:00:00",
"ScheduleEndTime": "2019-07-24T14:00:00",
"Technician": 161555,
"WOClientId": 1200,
"AffiliateId": 116531,
"WoTypeId": 70,
"ProjectId": 8637,
"IsLockedTechnician": false,
"Section": 2,
"OnSiteTime": 3600,
"PriorityId": 0,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 0,
"ServiceCodeId": 8164,
"ServiceTypeId": 1637,
"ServiceCategoryId": 96,
"IsScheduleAtRisk": false,
"IsDetach": false,
"LocationId": 808648,
"UTC": 0,
"DST": null,
"ConvertZipCode": true,
"Lat": 36.09564,
"Lng": -80.7957,
"ZipCode": "27020",
"State": "NC",
"Region": "Carolinas"
},
{
"Id": 2035476,
"StartTime": "2019-07-24T11:22:39",
"EndTime": "2019-07-24T13:10:38",
"ScheduleStartTime": "2019-07-24T10:00:00",
"ScheduleEndTime": "2019-07-24T14:00:00",
"Technician": 161555,
"WOClientId": 1200,
"AffiliateId": 116531,
"WoTypeId": 70,
"ProjectId": 8636,
"IsLockedTechnician": false,
"Section": 2,
"OnSiteTime": 3600,
"PriorityId": 0,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 0,
"ServiceCodeId": 8164,
"ServiceTypeId": 1637,
"ServiceCategoryId": 96,
"IsScheduleAtRisk": false,
"IsDetach": false,
"LocationId": 808646,
"UTC": 0,
"DST": null,
"ConvertZipCode": true,
"Lat": 35.575801,
"Lng": -80.819083,
"ZipCode": "28115",
"State": "NC",
"Region": "Carolinas"
},
{
"Id": 2035670,
"StartTime": "2019-07-24T11:22:39",
"EndTime": "2019-07-24T13:10:38",
"ScheduleStartTime": "2019-07-24T10:00:00",
"ScheduleEndTime": "2019-07-24T14:00:00",
"Technician": 161555,
"WOClientId": 1200,
"AffiliateId": 116531,
"WoTypeId": 30,
"ProjectId": 0,
"IsLockedTechnician": false,
"Section": 2,
"OnSiteTime": 3600,
"PriorityId": 0,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 0,
"ServiceCodeId": 5316,
"ServiceTypeId": 1248,
"ServiceCategoryId": 1,
"IsScheduleAtRisk": true,
"IsDetach": false,
"LocationId": 808646,
"UTC": 0,
"DST": null,
"ConvertZipCode": true,
"Lat": 35.575801,
"Lng": -80.819083,
"ZipCode": "28115",
"State": "NC",
"Region": "Carolinas"
},
{
"Id": 2036049,
"StartTime": "2019-07-25T08:00:00",
"EndTime": "2019-07-25T09:58:38",
"ScheduleStartTime": "2019-07-25T08:00:00",
"ScheduleEndTime": "2019-07-25T12:00:00",
"Technician": 161555,
"WOClientId": 1200,
"AffiliateId": 116531,
"WoTypeId": 70,
"ProjectId": 8652,
"IsLockedTechnician": false,
"Section": 1,
"OnSiteTime": 3600,
"PriorityId": 0,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 0,
"ServiceCodeId": 8164,
"ServiceTypeId": 1637,
"ServiceCategoryId": 96,
"IsScheduleAtRisk": false,
"IsDetach": false,
"LocationId": 808651,
"UTC": 0,
"DST": null,
"ConvertZipCode": true,
"Lat": 35.483897,
"Lng": -80.599575,
"ZipCode": "28083",
"State": "NC",
"Region": "Carolinas"
},
{
"Id": 0,
"StartTime": "2019-07-25T08:00:00",
"EndTime": "2019-07-25T09:58:38",
"ScheduleStartTime": "2019-07-25T08:00:00",
"ScheduleEndTime": "2019-07-25T12:00:00",
"Technician": 0,
"WOClientId": 1200,
"AffiliateId": 0,
"WoTypeId": 0,
"ProjectId": 8652,
"IsLockedTechnician": false,
"Section": 0,
"OnSiteTime": 3600,
"PriorityId": 9,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 1,
"ServiceCodeId": 8164,
"ServiceTypeId": 1637,
"ServiceCategoryId": 8164,
"IsScheduleAtRisk": false,
"IsDetach": false,
"LocationId": 808651,
"UTC": 0,
"DST": null,
"ConvertZipCode": false,
"Lat": 35.483897,
"Lng": -80.599575,
"ZipCode": "28083",
"State": null,
"Region": null
}
],
"IsSchedule": false,
"OnSiteTime": 0,
"IncrementSecond": 0,
"TotalDrivingTime": 9090,
"AtRiskWoIds": [
2035670
]
}

View File

@ -1,174 +0,0 @@
{
"TechnicianId": 161555,
"AffiliateId": 0,
"ScheduleStartTime": "2019-07-25T08:00:00",
"ScheduleEndTime": "2019-07-25T12:00:00",
"WorkOrders": [{
"Id": 2035478,
"StartTime": "2019-07-24T10:00:00",
"EndTime": "2019-07-24T11:22:39",
"ScheduleStartTime": "2019-07-24T10:00:00",
"ScheduleEndTime": "2019-07-24T14:00:00",
"Technician": 161555,
"WOClientId": 1200,
"AffiliateId": 116531,
"WoTypeId": 70,
"ProjectId": 8637,
"IsLockedTechnician": false,
"Section": 2,
"OnSiteTime": 3600,
"PriorityId": 0,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 0,
"ServiceCodeId": 8164,
"ServiceTypeId": 1637,
"ServiceCategoryId": 96,
"IsScheduleAtRisk": false,
"IsDetach": false,
"LocationId": 808648,
"UTC": 0,
"DST": null,
"ConvertZipCode": true,
"Lat": 36.09564,
"Lng": -80.7957,
"ZipCode": "27020",
"State": "NC",
"Region": "Carolinas"
},
{
"Id": 2035476,
"StartTime": "2019-07-24T11:22:39",
"EndTime": "2019-07-24T13:10:38",
"ScheduleStartTime": "2019-07-24T10:00:00",
"ScheduleEndTime": "2019-07-24T14:00:00",
"Technician": 161555,
"WOClientId": 1200,
"AffiliateId": 116531,
"WoTypeId": 70,
"ProjectId": 8636,
"IsLockedTechnician": false,
"Section": 2,
"OnSiteTime": 3600,
"PriorityId": 0,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 0,
"ServiceCodeId": 8164,
"ServiceTypeId": 1637,
"ServiceCategoryId": 96,
"IsScheduleAtRisk": false,
"IsDetach": false,
"LocationId": 808646,
"UTC": 0,
"DST": null,
"ConvertZipCode": true,
"Lat": 35.575801,
"Lng": -80.819083,
"ZipCode": "28115",
"State": "NC",
"Region": "Carolinas"
},
{
"Id": 2035670,
"StartTime": "2019-07-24T11:22:39",
"EndTime": "2019-07-24T13:10:38",
"ScheduleStartTime": "2019-07-24T10:00:00",
"ScheduleEndTime": "2019-07-24T14:00:00",
"Technician": 161555,
"WOClientId": 1200,
"AffiliateId": 116531,
"WoTypeId": 30,
"ProjectId": 0,
"IsLockedTechnician": false,
"Section": 2,
"OnSiteTime": 3600,
"PriorityId": 0,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 0,
"ServiceCodeId": 5316,
"ServiceTypeId": 1248,
"ServiceCategoryId": 1,
"IsScheduleAtRisk": true,
"IsDetach": false,
"LocationId": 808646,
"UTC": 0,
"DST": null,
"ConvertZipCode": true,
"Lat": 35.575801,
"Lng": -80.819083,
"ZipCode": "28115",
"State": "NC",
"Region": "Carolinas"
},
{
"Id": 2036049,
"StartTime": "2019-07-25T08:00:00",
"EndTime": "2019-07-25T09:58:38",
"ScheduleStartTime": "2019-07-25T08:00:00",
"ScheduleEndTime": "2019-07-25T12:00:00",
"Technician": 161555,
"WOClientId": 1200,
"AffiliateId": 116531,
"WoTypeId": 70,
"ProjectId": 8652,
"IsLockedTechnician": false,
"Section": 1,
"OnSiteTime": 3600,
"PriorityId": 0,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 0,
"ServiceCodeId": 8164,
"ServiceTypeId": 1637,
"ServiceCategoryId": 96,
"IsScheduleAtRisk": false,
"IsDetach": false,
"LocationId": 808651,
"UTC": 0,
"DST": null,
"ConvertZipCode": true,
"Lat": 35.483897,
"Lng": -80.599575,
"ZipCode": "28083",
"State": "NC",
"Region": "Carolinas"
},
{
"Id": 0,
"StartTime": "2019-07-25T08:00:00",
"EndTime": "2019-07-25T09:58:38",
"ScheduleStartTime": "2019-07-25T08:00:00",
"ScheduleEndTime": "2019-07-25T12:00:00",
"Technician": 0,
"WOClientId": 1200,
"AffiliateId": 0,
"WoTypeId": 0,
"ProjectId": 8652,
"IsLockedTechnician": false,
"Section": 0,
"OnSiteTime": 3600,
"PriorityId": 9,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 1,
"ServiceCodeId": 8164,
"ServiceTypeId": 1637,
"ServiceCategoryId": 8164,
"IsScheduleAtRisk": false,
"IsDetach": false,
"LocationId": 808651,
"UTC": 0,
"DST": null,
"ConvertZipCode": false,
"Lat": 35.483897,
"Lng": -80.599575,
"ZipCode": "28083",
"State": null,
"Region": null
}
],
"IsSchedule": false,
"OnSiteTime": 0,
"IncrementSecond": 0,
"TotalDrivingTime": 9090,
"AtRiskWoIds": [
2035670
]
}

View File

@ -1,174 +0,0 @@
{
"TechnicianId": 161555,
"AffiliateId": 0,
"ScheduleStartTime": "2019-07-25T08:00:00",
"ScheduleEndTime": "2019-07-25T12:00:00",
"WorkOrders": [{
"Id": 2035478,
"StartTime": "2019-07-24T10:00:00",
"EndTime": "2019-07-24T11:22:39",
"ScheduleStartTime": "2019-07-24T10:00:00",
"ScheduleEndTime": "2019-07-24T14:00:00",
"Technician": 161555,
"WOClientId": 1200,
"AffiliateId": 116531,
"WoTypeId": 70,
"ProjectId": 8637,
"IsLockedTechnician": false,
"Section": 2,
"OnSiteTime": 3600,
"PriorityId": 0,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 0,
"ServiceCodeId": 8164,
"ServiceTypeId": 1637,
"ServiceCategoryId": 96,
"IsScheduleAtRisk": false,
"IsDetach": false,
"LocationId": 808648,
"UTC": 0,
"DST": null,
"ConvertZipCode": true,
"Lat": 36.09564,
"Lng": -80.7957,
"ZipCode": "27020",
"State": "NC",
"Region": "Carolinas"
},
{
"Id": 2035476,
"StartTime": "2019-07-24T11:22:39",
"EndTime": "2019-07-24T13:10:38",
"ScheduleStartTime": "2019-07-24T10:00:00",
"ScheduleEndTime": "2019-07-24T14:00:00",
"Technician": 161555,
"WOClientId": 1200,
"AffiliateId": 116531,
"WoTypeId": 70,
"ProjectId": 8636,
"IsLockedTechnician": false,
"Section": 2,
"OnSiteTime": 3600,
"PriorityId": 0,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 0,
"ServiceCodeId": 8164,
"ServiceTypeId": 1637,
"ServiceCategoryId": 96,
"IsScheduleAtRisk": false,
"IsDetach": false,
"LocationId": 808646,
"UTC": 0,
"DST": null,
"ConvertZipCode": true,
"Lat": 35.575801,
"Lng": -80.819083,
"ZipCode": "28115",
"State": "NC",
"Region": "Carolinas"
},
{
"Id": 2035670,
"StartTime": "2019-07-24T11:22:39",
"EndTime": "2019-07-24T13:10:38",
"ScheduleStartTime": "2019-07-24T10:00:00",
"ScheduleEndTime": "2019-07-24T14:00:00",
"Technician": 161555,
"WOClientId": 1200,
"AffiliateId": 116531,
"WoTypeId": 30,
"ProjectId": 0,
"IsLockedTechnician": false,
"Section": 2,
"OnSiteTime": 3600,
"PriorityId": 0,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 0,
"ServiceCodeId": 5316,
"ServiceTypeId": 1248,
"ServiceCategoryId": 1,
"IsScheduleAtRisk": true,
"IsDetach": false,
"LocationId": 808646,
"UTC": 0,
"DST": null,
"ConvertZipCode": true,
"Lat": 35.575801,
"Lng": -80.819083,
"ZipCode": "28115",
"State": "NC",
"Region": "Carolinas"
},
{
"Id": 2036049,
"StartTime": "2019-07-25T08:00:00",
"EndTime": "2019-07-25T09:58:38",
"ScheduleStartTime": "2019-07-25T08:00:00",
"ScheduleEndTime": "2019-07-25T12:00:00",
"Technician": 161555,
"WOClientId": 1200,
"AffiliateId": 116531,
"WoTypeId": 70,
"ProjectId": 8652,
"IsLockedTechnician": false,
"Section": 1,
"OnSiteTime": 3600,
"PriorityId": 0,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 0,
"ServiceCodeId": 8164,
"ServiceTypeId": 1637,
"ServiceCategoryId": 96,
"IsScheduleAtRisk": false,
"IsDetach": false,
"LocationId": 808651,
"UTC": 0,
"DST": null,
"ConvertZipCode": true,
"Lat": 35.483897,
"Lng": -80.599575,
"ZipCode": "28083",
"State": "NC",
"Region": "Carolinas"
},
{
"Id": 0,
"StartTime": "2019-07-25T08:00:00",
"EndTime": "2019-07-25T09:58:38",
"ScheduleStartTime": "2019-07-25T08:00:00",
"ScheduleEndTime": "2019-07-25T12:00:00",
"Technician": 0,
"WOClientId": 1200,
"AffiliateId": 0,
"WoTypeId": 0,
"ProjectId": 8652,
"IsLockedTechnician": false,
"Section": 0,
"OnSiteTime": 3600,
"PriorityId": 9,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 1,
"ServiceCodeId": 8164,
"ServiceTypeId": 1637,
"ServiceCategoryId": 8164,
"IsScheduleAtRisk": false,
"IsDetach": false,
"LocationId": 808651,
"UTC": 0,
"DST": null,
"ConvertZipCode": false,
"Lat": 35.483897,
"Lng": -80.599575,
"ZipCode": "28083",
"State": null,
"Region": null
}
],
"IsSchedule": false,
"OnSiteTime": 0,
"IncrementSecond": 0,
"TotalDrivingTime": 9090,
"AtRiskWoIds": [
2035670
]
}

View File

@ -1,174 +0,0 @@
{
"TechnicianId": 161555,
"AffiliateId": 0,
"ScheduleStartTime": "2019-07-25T08:00:00",
"ScheduleEndTime": "2019-07-25T12:00:00",
"WorkOrders": [{
"Id": 2035478,
"StartTime": "2019-07-24T10:00:00",
"EndTime": "2019-07-24T11:22:39",
"ScheduleStartTime": "2019-07-24T10:00:00",
"ScheduleEndTime": "2019-07-24T14:00:00",
"Technician": 161555,
"WOClientId": 1200,
"AffiliateId": 116531,
"WoTypeId": 70,
"ProjectId": 8637,
"IsLockedTechnician": false,
"Section": 2,
"OnSiteTime": 3600,
"PriorityId": 0,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 0,
"ServiceCodeId": 8164,
"ServiceTypeId": 1637,
"ServiceCategoryId": 96,
"IsScheduleAtRisk": false,
"IsDetach": false,
"LocationId": 808648,
"UTC": 0,
"DST": null,
"ConvertZipCode": true,
"Lat": 36.09564,
"Lng": -80.7957,
"ZipCode": "27020",
"State": "NC",
"Region": "Carolinas"
},
{
"Id": 2035476,
"StartTime": "2019-07-24T11:22:39",
"EndTime": "2019-07-24T13:10:38",
"ScheduleStartTime": "2019-07-24T10:00:00",
"ScheduleEndTime": "2019-07-24T14:00:00",
"Technician": 161555,
"WOClientId": 1200,
"AffiliateId": 116531,
"WoTypeId": 70,
"ProjectId": 8636,
"IsLockedTechnician": false,
"Section": 2,
"OnSiteTime": 3600,
"PriorityId": 0,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 0,
"ServiceCodeId": 8164,
"ServiceTypeId": 1637,
"ServiceCategoryId": 96,
"IsScheduleAtRisk": false,
"IsDetach": false,
"LocationId": 808646,
"UTC": 0,
"DST": null,
"ConvertZipCode": true,
"Lat": 35.575801,
"Lng": -80.819083,
"ZipCode": "28115",
"State": "NC",
"Region": "Carolinas"
},
{
"Id": 2035670,
"StartTime": "2019-07-24T11:22:39",
"EndTime": "2019-07-24T13:10:38",
"ScheduleStartTime": "2019-07-24T10:00:00",
"ScheduleEndTime": "2019-07-24T14:00:00",
"Technician": 161555,
"WOClientId": 1200,
"AffiliateId": 116531,
"WoTypeId": 30,
"ProjectId": 0,
"IsLockedTechnician": false,
"Section": 2,
"OnSiteTime": 3600,
"PriorityId": 0,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 0,
"ServiceCodeId": 5316,
"ServiceTypeId": 1248,
"ServiceCategoryId": 1,
"IsScheduleAtRisk": true,
"IsDetach": false,
"LocationId": 808646,
"UTC": 0,
"DST": null,
"ConvertZipCode": true,
"Lat": 35.575801,
"Lng": -80.819083,
"ZipCode": "28115",
"State": "NC",
"Region": "Carolinas"
},
{
"Id": 2036049,
"StartTime": "2019-07-25T08:00:00",
"EndTime": "2019-07-25T09:58:38",
"ScheduleStartTime": "2019-07-25T08:00:00",
"ScheduleEndTime": "2019-07-25T12:00:00",
"Technician": 161555,
"WOClientId": 1200,
"AffiliateId": 116531,
"WoTypeId": 70,
"ProjectId": 8652,
"IsLockedTechnician": false,
"Section": 1,
"OnSiteTime": 3600,
"PriorityId": 0,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 0,
"ServiceCodeId": 8164,
"ServiceTypeId": 1637,
"ServiceCategoryId": 96,
"IsScheduleAtRisk": false,
"IsDetach": false,
"LocationId": 808651,
"UTC": 0,
"DST": null,
"ConvertZipCode": true,
"Lat": 35.483897,
"Lng": -80.599575,
"ZipCode": "28083",
"State": "NC",
"Region": "Carolinas"
},
{
"Id": 0,
"StartTime": "2019-07-25T08:00:00",
"EndTime": "2019-07-25T09:58:38",
"ScheduleStartTime": "2019-07-25T08:00:00",
"ScheduleEndTime": "2019-07-25T12:00:00",
"Technician": 0,
"WOClientId": 1200,
"AffiliateId": 0,
"WoTypeId": 0,
"ProjectId": 8652,
"IsLockedTechnician": false,
"Section": 0,
"OnSiteTime": 3600,
"PriorityId": 9,
"ToTechnicianDrivingTime": 0,
"InsertWoSort": 1,
"ServiceCodeId": 8164,
"ServiceTypeId": 1637,
"ServiceCategoryId": 8164,
"IsScheduleAtRisk": false,
"IsDetach": false,
"LocationId": 808651,
"UTC": 0,
"DST": null,
"ConvertZipCode": false,
"Lat": 35.483897,
"Lng": -80.599575,
"ZipCode": "28083",
"State": null,
"Region": null
}
],
"IsSchedule": false,
"OnSiteTime": 0,
"IncrementSecond": 0,
"TotalDrivingTime": 9090,
"AtRiskWoIds": [
2035670
]
}

View File

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PackageRequirementsSettings">
<option name="requirementsPath" value="" />
</component>
<component name="TestRunnerService">
<option name="PROJECT_TEST_RUNNER" value="pytest" />
</component>
</module>

View File

@ -1,6 +0,0 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6" project-jdk-type="Python SDK" />
</project>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/WebUiPy36.iml" filepath="$PROJECT_DIR$/.idea/WebUiPy36.iml" />
</modules>
</component>
</project>

View File

@ -1,169 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="063831f7-0198-40fb-ba64-766a49951e4c" name="Default Changelist" comment="" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="Python Script" />
</list>
</option>
</component>
<component name="ProjectId" id="1p3FqnBRtmnXqrsKpEyYq6InGOw" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showExcludedFiles" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
<property name="last_opened_file_path" value="$PROJECT_DIR$/../TestDeveloperPlatform36" />
<property name="settings.editor.selected.configurable" value="com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable" />
</component>
<component name="RunManager" selected="Python.practice">
<configuration name="practice" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="WebUiPy36" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/practice.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="test_baidu" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="WebUiPy36" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/test_baidu.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="pytest in test_login.py" type="tests" factoryName="py.test" temporary="true" nameIsGenerated="true">
<module name="WebUiPy36" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<option name="_new_keywords" value="&quot;&quot;" />
<option name="_new_additionalArguments" value="&quot;&quot;" />
<option name="_new_target" value="&quot;$PROJECT_DIR$/test_login.py&quot;" />
<option name="_new_targetType" value="&quot;PATH&quot;" />
<method v="2" />
</configuration>
<recent_temporary>
<list>
<item itemvalue="Python.practice" />
<item itemvalue="Python tests.pytest in test_login.py" />
<item itemvalue="Python.test_baidu" />
</list>
</recent_temporary>
</component>
<component name="ServiceViewManager">
<option name="viewStates">
<list>
<serviceView>
<treeState>
<expand />
<select />
</treeState>
</serviceView>
</list>
</option>
</component>
<component name="SvnConfiguration">
<configuration />
</component>
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="063831f7-0198-40fb-ba64-766a49951e4c" name="Default Changelist" comment="" />
<created>1614404059892</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1614404059892</updated>
</task>
<servers />
</component>
<component name="WindowStateProjectService">
<state x="503" y="174" key="EnvironmentVariablesDialog" timestamp="1614404285113">
<screen x="0" y="0" width="1536" height="824" />
</state>
<state x="503" y="174" key="EnvironmentVariablesDialog/0.0.1536.824@0.0.1536.824" timestamp="1614404285113" />
<state x="549" y="168" key="FileChooserDialogImpl" timestamp="1615470175929">
<screen x="0" y="0" width="1536" height="824" />
</state>
<state x="549" y="168" key="FileChooserDialogImpl/0.0.1536.824@0.0.1536.824" timestamp="1615470175929" />
<state width="1515" height="104" key="GridCell.Tab.0.bottom" timestamp="1615387370026">
<screen x="0" y="0" width="1536" height="824" />
</state>
<state width="1515" height="104" key="GridCell.Tab.0.bottom/0.0.1536.824@0.0.1536.824" timestamp="1615387370026" />
<state width="1515" height="104" key="GridCell.Tab.0.center" timestamp="1615387370026">
<screen x="0" y="0" width="1536" height="824" />
</state>
<state width="1515" height="104" key="GridCell.Tab.0.center/0.0.1536.824@0.0.1536.824" timestamp="1615387370026" />
<state width="1515" height="104" key="GridCell.Tab.0.left" timestamp="1615387370026">
<screen x="0" y="0" width="1536" height="824" />
</state>
<state width="1515" height="104" key="GridCell.Tab.0.left/0.0.1536.824@0.0.1536.824" timestamp="1615387370026" />
<state width="1515" height="104" key="GridCell.Tab.0.right" timestamp="1615387370026">
<screen x="0" y="0" width="1536" height="824" />
</state>
<state width="1515" height="104" key="GridCell.Tab.0.right/0.0.1536.824@0.0.1536.824" timestamp="1615387370026" />
<state width="1515" height="261" key="GridCell.Tab.1.bottom" timestamp="1614954899410">
<screen x="0" y="0" width="1536" height="824" />
</state>
<state width="1515" height="261" key="GridCell.Tab.1.bottom/0.0.1536.824@0.0.1536.824" timestamp="1614954899410" />
<state width="1515" height="261" key="GridCell.Tab.1.center" timestamp="1614954899410">
<screen x="0" y="0" width="1536" height="824" />
</state>
<state width="1515" height="261" key="GridCell.Tab.1.center/0.0.1536.824@0.0.1536.824" timestamp="1614954899410" />
<state width="1515" height="261" key="GridCell.Tab.1.left" timestamp="1614954899410">
<screen x="0" y="0" width="1536" height="824" />
</state>
<state width="1515" height="261" key="GridCell.Tab.1.left/0.0.1536.824@0.0.1536.824" timestamp="1614954899410" />
<state width="1515" height="261" key="GridCell.Tab.1.right" timestamp="1614954899410">
<screen x="0" y="0" width="1536" height="824" />
</state>
<state width="1515" height="261" key="GridCell.Tab.1.right/0.0.1536.824@0.0.1536.824" timestamp="1614954899410" />
<state x="270" y="55" key="SettingsEditor" timestamp="1614405157675">
<screen x="0" y="0" width="1536" height="824" />
</state>
<state x="270" y="55" key="SettingsEditor/0.0.1536.824@0.0.1536.824" timestamp="1614405157675" />
<state x="431" y="145" width="672" height="678" key="search.everywhere.popup" timestamp="1614781810714">
<screen x="0" y="0" width="1536" height="824" />
</state>
<state x="431" y="145" width="672" height="678" key="search.everywhere.popup/0.0.1536.824@0.0.1536.824" timestamp="1614781810714" />
</component>
</project>

View File

@ -1,177 +0,0 @@
body {
font-family: Helvetica, Arial, sans-serif;
font-size: 12px;
/* do not increase min-width as some may use split screens */
min-width: 800px;
color: #999;
}
h1 {
font-size: 24px;
color: black;
}
h2 {
font-size: 16px;
color: black;
}
p {
color: black;
}
a {
color: #999;
}
table {
border-collapse: collapse;
}
/******************************
* SUMMARY INFORMATION
******************************/
#environment td {
padding: 5px;
border: 1px solid #E6E6E6;
}
#environment tr:nth-child(odd) {
background-color: #f6f6f6;
}
/******************************
* TEST RESULT COLORS
******************************/
span.passed, .passed .col-result {
color: green;
}
span.skipped, span.xfailed, span.rerun, .skipped .col-result, .xfailed .col-result, .rerun .col-result {
color: orange;
}
span.error, span.failed, span.xpassed, .error .col-result, .failed .col-result, .xpassed .col-result {
color: red;
}
/******************************
* RESULTS TABLE
*
* 1. Table Layout
* 2. Extra
* 3. Sorting items
*
******************************/
/*------------------
* 1. Table Layout
*------------------*/
#results-table {
border: 1px solid #e6e6e6;
color: #999;
font-size: 12px;
width: 100%
}
#results-table th, #results-table td {
padding: 5px;
border: 1px solid #E6E6E6;
text-align: left
}
#results-table th {
font-weight: bold
}
/*------------------
* 2. Extra
*------------------*/
.log:only-child {
height: inherit
}
.log {
background-color: #e6e6e6;
border: 1px solid #e6e6e6;
color: black;
display: block;
font-family: "Courier New", Courier, monospace;
height: 230px;
overflow-y: scroll;
padding: 5px;
white-space: pre-wrap
}
div.image {
border: 1px solid #e6e6e6;
float: right;
height: 240px;
margin-left: 5px;
overflow: hidden;
width: 320px
}
div.image img {
width: 320px
}
div.video {
border: 1px solid #e6e6e6;
float: right;
height: 240px;
margin-left: 5px;
overflow: hidden;
width: 320px
}
div.video video {
overflow: hidden;
width: 320px;
height: 240px;
}
.collapsed {
display: none;
}
.expander::after {
content: " (show details)";
color: #BBB;
font-style: italic;
cursor: pointer;
}
.collapser::after {
content: " (hide details)";
color: #BBB;
font-style: italic;
cursor: pointer;
}
/*------------------
* 3. Sorting items
*------------------*/
.sortable {
cursor: pointer;
}
.sort-icon {
font-size: 0px;
float: left;
margin-right: 5px;
margin-top: 5px;
/*triangle*/
width: 0;
height: 0;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
}
.inactive .sort-icon {
/*finish triangle*/
border-top: 8px solid #E6E6E6;
}
.asc.active .sort-icon {
/*finish triangle*/
border-bottom: 8px solid #999;
}
.desc.active .sort-icon {
/*finish triangle*/
border-top: 8px solid #999;
}

View File

@ -1,24 +0,0 @@
// 封装一个函数
function assignClass(name, age){
// 定义变量 方式一
var name = name
// 定义变量 方式二 推荐
let age = age
if (age >= 3){
window.alert(name + " 应该分配到小班")
}
else if (age>=4){
window.alert(name + " 应该分配到中班")
}
else if (age >=5){
window.alert(name + " 应该分配到大班")
}
else{
window.alert(name + " 未达到入园年级")
}
}
// 调用函数
assignClass("flora", 3)

View File

@ -1,44 +0,0 @@
utl = "https://www.ketangpai.com/#/homePage"
# 首页 tab
//div[@id='tab-/homePage']
# 产品功能 tab
//div[@id='tab-/productFunction']
// 机构版 tab
//div[@id='tab-/mechanism']
// 其他tab定位类似 不写了
// 切换旧版本 按钮
//span[contains(text(), ' 切换旧版本 ')]
// 进入课堂按钮
//span[contains(text(), '进入课堂')]
url = "https://www.ketangpai.com/#/main"
//我的课堂
//li[@role='menuitem' and text()='我的课堂']
// 加入课程
//span[text()='加入课程 ']
// 待办事项 - 查看全部
//div[text()=' 查看全部 ']
// 置顶课堂 - python36期
//h2[text()='置顶课程']/../following-sibling::div//h3[text()='Python自动化第36期']
// 置顶课程 - 指定作业
//h2[text()='置顶课程']/..//following-sibling::div//p[starts-with(text(), '0303-开放性题目')]
// 返回所有的(负责人:妮妮)的第一个
(//div[contains(text(), '负责人:妮妮')])[1]
// 搜索我学的课程
//input[@placeholder='搜索我学的课程']
// 侧边栏 - 会话
//span[@class='name' and text()='会话']

View File

@ -1,62 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Login</title>
<style type="text/css">
.login{
height: 60px;
width: 311px;
font-size: 38px;
margin-left:240px;
}
.info{
margin-top:10px;
margin-bottom:10px;
margin-right:50px;
margin-left:50px;
font-size: 28px;
}
.input, select{
height: 30px;
width: 300px;
font-size: 18px;
}
.submit{
height: 40px;
width: 100px;
font-size: 28px;
margin-left:300px;
color: blue;
}
</style>
</head>
<body>
<form action="http://httpbin.org/post" method="post">
<div>
<div class="login">
<span>Login</span>
</div>
<div class="info">
username: <input id="user" name="username" placeholder="Please input your username" class="input"/>
</div>
<div class="info">
password: <input id="pwd" name="password" type="password" placeholder="Please type your password" class="input"/>
</div>
<div class="info">
<select id="role" class="select">
<option value="0">admin</option>
<option value="1">OM</option>
<option value="2">AM</option>
<option value="3">VP</option>
</select>
</div>
<div class="info">
<input id="submitbtn" name="submit" type="submit" class="submit" />
</div>
</div>
</form>
</body>
</html>

View File

@ -1,21 +0,0 @@
"""
======================================
Author: Flora.Chen
Time: 2021/3/5 22:24
~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~
======================================
"""
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
driver = webdriver.Chrome()
driver.implicitly_wait(10)
driver.get("https://www.12306.cn/index/")
time.sleep(5)
elem = driver.find_element(By.XPATH, "//h2[text()='友情链接'")
# 将元素滚动到元素可见
elem.location_once_scrolled_into_view
time.sleep(2)

View File

@ -1,282 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Test Report</title>
<link href="assets/style.css" rel="stylesheet" type="text/css"/></head>
<body onLoad="init()">
<script>/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
function toArray(iter) {
if (iter === null) {
return null;
}
return Array.prototype.slice.call(iter);
}
function find(selector, elem) {
if (!elem) {
elem = document;
}
return elem.querySelector(selector);
}
function find_all(selector, elem) {
if (!elem) {
elem = document;
}
return toArray(elem.querySelectorAll(selector));
}
function sort_column(elem) {
toggle_sort_states(elem);
var colIndex = toArray(elem.parentNode.childNodes).indexOf(elem);
var key;
if (elem.classList.contains('numeric')) {
key = key_num;
} else if (elem.classList.contains('result')) {
key = key_result;
} else {
key = key_alpha;
}
sort_table(elem, key(colIndex));
}
function show_all_extras() {
find_all('.col-result').forEach(show_extras);
}
function hide_all_extras() {
find_all('.col-result').forEach(hide_extras);
}
function show_extras(colresult_elem) {
var extras = colresult_elem.parentNode.nextElementSibling;
var expandcollapse = colresult_elem.firstElementChild;
extras.classList.remove("collapsed");
expandcollapse.classList.remove("expander");
expandcollapse.classList.add("collapser");
}
function hide_extras(colresult_elem) {
var extras = colresult_elem.parentNode.nextElementSibling;
var expandcollapse = colresult_elem.firstElementChild;
extras.classList.add("collapsed");
expandcollapse.classList.remove("collapser");
expandcollapse.classList.add("expander");
}
function show_filters() {
var filter_items = document.getElementsByClassName('filter');
for (var i = 0; i < filter_items.length; i++)
filter_items[i].hidden = false;
}
function add_collapse() {
// Add links for show/hide all
var resulttable = find('table#results-table');
var showhideall = document.createElement("p");
showhideall.innerHTML = '<a href="javascript:show_all_extras()">Show all details</a> / ' +
'<a href="javascript:hide_all_extras()">Hide all details</a>';
resulttable.parentElement.insertBefore(showhideall, resulttable);
// Add show/hide link to each result
find_all('.col-result').forEach(function(elem) {
var collapsed = get_query_parameter('collapsed') || 'Passed';
var extras = elem.parentNode.nextElementSibling;
var expandcollapse = document.createElement("span");
if (extras.classList.contains("collapsed")) {
expandcollapse.classList.add("expander")
} else if (collapsed.includes(elem.innerHTML)) {
extras.classList.add("collapsed");
expandcollapse.classList.add("expander");
} else {
expandcollapse.classList.add("collapser");
}
elem.appendChild(expandcollapse);
elem.addEventListener("click", function(event) {
if (event.currentTarget.parentNode.nextElementSibling.classList.contains("collapsed")) {
show_extras(event.currentTarget);
} else {
hide_extras(event.currentTarget);
}
});
})
}
function get_query_parameter(name) {
var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
}
function init () {
reset_sort_headers();
add_collapse();
show_filters();
sort_column(find('.initial-sort'));
find_all('.sortable').forEach(function(elem) {
elem.addEventListener("click",
function(event) {
sort_column(elem);
}, false)
});
};
function sort_table(clicked, key_func) {
var rows = find_all('.results-table-row');
var reversed = !clicked.classList.contains('asc');
var sorted_rows = sort(rows, key_func, reversed);
/* Whole table is removed here because browsers acts much slower
* when appending existing elements.
*/
var thead = document.getElementById("results-table-head");
document.getElementById('results-table').remove();
var parent = document.createElement("table");
parent.id = "results-table";
parent.appendChild(thead);
sorted_rows.forEach(function(elem) {
parent.appendChild(elem);
});
document.getElementsByTagName("BODY")[0].appendChild(parent);
}
function sort(items, key_func, reversed) {
var sort_array = items.map(function(item, i) {
return [key_func(item), i];
});
sort_array.sort(function(a, b) {
var key_a = a[0];
var key_b = b[0];
if (key_a == key_b) return 0;
if (reversed) {
return (key_a < key_b ? 1 : -1);
} else {
return (key_a > key_b ? 1 : -1);
}
});
return sort_array.map(function(item) {
var index = item[1];
return items[index];
});
}
function key_alpha(col_index) {
return function(elem) {
return elem.childNodes[1].childNodes[col_index].firstChild.data.toLowerCase();
};
}
function key_num(col_index) {
return function(elem) {
return parseFloat(elem.childNodes[1].childNodes[col_index].firstChild.data);
};
}
function key_result(col_index) {
return function(elem) {
var strings = ['Error', 'Failed', 'Rerun', 'XFailed', 'XPassed',
'Skipped', 'Passed'];
return strings.indexOf(elem.childNodes[1].childNodes[col_index].firstChild.data);
};
}
function reset_sort_headers() {
find_all('.sort-icon').forEach(function(elem) {
elem.parentNode.removeChild(elem);
});
find_all('.sortable').forEach(function(elem) {
var icon = document.createElement("div");
icon.className = "sort-icon";
icon.textContent = "vvv";
elem.insertBefore(icon, elem.firstChild);
elem.classList.remove("desc", "active");
elem.classList.add("asc", "inactive");
});
}
function toggle_sort_states(elem) {
//if active, toggle between asc and desc
if (elem.classList.contains('active')) {
elem.classList.toggle('asc');
elem.classList.toggle('desc');
}
//if inactive, reset all other functions and add ascending active
if (elem.classList.contains('inactive')) {
reset_sort_headers();
elem.classList.remove('inactive');
elem.classList.add('active');
}
}
function is_all_rows_hidden(value) {
return value.hidden == false;
}
function filter_table(elem) {
var outcome_att = "data-test-result";
var outcome = elem.getAttribute(outcome_att);
class_outcome = outcome + " results-table-row";
var outcome_rows = document.getElementsByClassName(class_outcome);
for(var i = 0; i < outcome_rows.length; i++){
outcome_rows[i].hidden = !elem.checked;
}
var rows = find_all('.results-table-row').filter(is_all_rows_hidden);
var all_rows_hidden = rows.length == 0 ? true : false;
var not_found_message = document.getElementById("not-found-message");
not_found_message.hidden = !all_rows_hidden;
}
</script>
<h1>result.html</h1>
<p>Report generated on 27-Feb-2021 at 14:06:34 by <a href="https://pypi.python.org/pypi/pytest-html">pytest-html</a> v2.1.1</p>
<h2>Environment</h2>
<table id="environment">
<tr>
<td>Packages</td>
<td>{"pluggy": "0.13.1", "py": "1.8.1", "pytest": "5.4.1"}</td></tr>
<tr>
<td>Platform</td>
<td>Windows-10-10.0.18362-SP0</td></tr>
<tr>
<td>Plugins</td>
<td>{"Faker": "6.1.1", "allure-pytest": "2.8.12", "html": "2.1.1", "metadata": "1.8.0"}</td></tr>
<tr>
<td>Python</td>
<td>3.6.4</td></tr></table>
<h2>Summary</h2>
<p>1 tests ran in 9.59 seconds. </p>
<p class="filter" hidden="true">(Un)check the boxes to filter the results.</p><input checked="true" class="filter" data-test-result="passed" hidden="true" name="filter_checkbox" onChange="filter_table(this)" type="checkbox"/><span class="passed">1 passed</span>, <input checked="true" class="filter" data-test-result="skipped" disabled="true" hidden="true" name="filter_checkbox" onChange="filter_table(this)" type="checkbox"/><span class="skipped">0 skipped</span>, <input checked="true" class="filter" data-test-result="failed" disabled="true" hidden="true" name="filter_checkbox" onChange="filter_table(this)" type="checkbox"/><span class="failed">0 failed</span>, <input checked="true" class="filter" data-test-result="error" disabled="true" hidden="true" name="filter_checkbox" onChange="filter_table(this)" type="checkbox"/><span class="error">0 errors</span>, <input checked="true" class="filter" data-test-result="xfailed" disabled="true" hidden="true" name="filter_checkbox" onChange="filter_table(this)" type="checkbox"/><span class="xfailed">0 expected failures</span>, <input checked="true" class="filter" data-test-result="xpassed" disabled="true" hidden="true" name="filter_checkbox" onChange="filter_table(this)" type="checkbox"/><span class="xpassed">0 unexpected passes</span>
<h2>Results</h2>
<table id="results-table">
<thead id="results-table-head">
<tr>
<th class="sortable result initial-sort" col="result">Result</th>
<th class="sortable" col="name">Test</th>
<th class="sortable numeric" col="duration">Duration</th>
<th>Links</th></tr>
<tr hidden="true" id="not-found-message">
<th colspan="4">No results found. Try to check the filters</th></tr></thead>
<tbody class="passed results-table-row">
<tr>
<td class="col-result">Passed</td>
<td class="col-name">test_baidu.py::test_baidu</td>
<td class="col-duration">9.31</td>
<td class="col-links"></td></tr>
<tr>
<td class="extra" colspan="4">
<div class="empty log">No log output captured.</div></td></tr></tbody></table></body></html>

View File

@ -1,76 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>WEB Test</title>
<style type="text/css">
h4{
color:red
}
</style>
<!--
<style type="text/css">
h4{
color:red
}
伪元素 html中看不到这个元素就定位不到
h4::before{
content:"hello"
}
</style>
-->
</head>
<body>
<!-- 表单 前后端进行用户数据交互的一种方式-->
<form action="http://httpbin.org/post" method="post">
<div>
<h4>标题</h4>
<!-- 段落 -->
<p>这是一个段落</p>
<a href="http://www.baidu.com">
<img src="https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=3363295869,2467511306&fm=26&gp=0.jpg" width="100" height="100">
</a>
</div>
<!-- 在一个html中嵌套另一个页面 -->
<div>
<iframe src="http://www.baidu.com" width="100" height="200">
</iframe>
</div>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<!-- 用户输入 默认是type="text"可省略 -->
username: <input name="username" type="text" placeholder="请输入用户名" disabled/>
password: <input name="password" type="password" readonly/>
<div>
<!-- 进行单选时name属性要保持一致 -->
选择你的性别:
<input type="radio" name="sex" value="male"/>
<input type="radio" name="sex" value=""female/>
</div>
<div>
<!-- 进行单选时name属性要保持一致 -->
你最喜欢吃的食物:
<input type="checkbox" name="food" value="apple"/>苹果
<input type="checkbox" name="food" value="banana"/>香蕉
</div>
<div>
选择头像:<input type="file" name="avatar" />
</div>
选择你的爱好:
<select>
<option>打球</option>
<option>钓鱼</option>
<option>看书</option>
</select>
<input type="submit" />
</form>
</body>
</html>

View File

@ -1,203 +0,0 @@
from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
import time, pytest
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
class TestHomeWork:
"""
家庭作业
"""
@pytest.fixture
def init_driver(self):
driver = webdriver.Chrome()
driver.implicitly_wait(2)
yield driver
driver.quit()
def test_homework_01(self, init_driver):
"""
作业一
1进入百度
2输入柠檬班
3定位柠檬班腾讯课堂点击进入
4定位腾讯课堂页面的任意元素
注意所有元素定位练习显性等待的用法
:return: None
"""
# 进入百度
init_driver.get("https://www.baidu.com/")
# 输入柠檬班
WebDriverWait(init_driver, 10, 0.1).until(
EC.visibility_of_element_located(("id", "kw"))
).send_keys("柠檬班")
# 点击 百度一下 按钮
WebDriverWait(init_driver, 10, 0.1).until(
EC.element_to_be_clickable(("id", "su"))
).click()
time.sleep(2)
assert init_driver.title == "柠檬班_百度搜索"
# 定位柠檬班腾讯课堂,点击进入
located = "(//em[text()='柠檬班']/parent::a[text()='腾讯课堂官网'])[1]"
WebDriverWait(init_driver, 10, 0.1).until(
EC.presence_of_element_located(("xpath", located))
).click()
# 切换窗口
# 获取所有的窗口句柄
all_handles = init_driver.window_handles
WebDriverWait(init_driver, 10, 0.1).until(
EC.new_window_is_opened(all_handles)
)
init_driver.switch_to.window(init_driver.window_handles[-1])
assert init_driver.title == "柠檬班_柠檬班腾讯课堂官网"
# 定位腾讯课堂页面的任意元素
located = "//span[text()='立即报名']"
# 点击立即报名
WebDriverWait(init_driver, 10, 0.1).until(
EC.presence_of_element_located(("xpath", located))
).click()
# 切换窗口
init_driver.switch_to.window(init_driver.window_handles[-1])
assert "软件测试之python全栈自动化测试工程师" in init_driver.title
def test_homework_02(self, init_driver):
"""
作业二
https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable 通过代码完成该网址的鼠标拖拽动作
:return: None
"""
init_driver.get("https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable")
# 等待iframe可见并切换
WebDriverWait(init_driver, 10, 0.2).until(
EC.frame_to_be_available_and_switch_to_it(("xpath", "//iframe[@id='iframeResult']"))
)
# 等待元素可见
elem_01 = WebDriverWait(init_driver, 10, 0.2).until(
EC.visibility_of_element_located(("xpath", "//div[contains(text(), '请拖拽我')]"))
)
elem_02 = WebDriverWait(init_driver, 10, 0.2).until(
EC.visibility_of_element_located(("xpath", "//div[contains(text(), '请放置到这里')]"))
)
# elem_01 = init_driver.find_element("xpath", "//div[contains(text(), '请拖拽我')]")
# elem_02 = init_driver.find_element("xpath", "//div[contains(text(), '请放置到这里')]")
# 创建一个鼠标操作对象
action = ActionChains(init_driver)
# 将元素1拖拽到元素2所在位置
action.drag_and_drop(elem_01, elem_02).perform()
try:
# 切换到弹窗 并点击关闭
WebDriverWait(init_driver, 10, 0.1).until(
EC.alert_is_present()
)
alert = init_driver.switch_to.alert
alert.accept()
time.sleep(2)
except Exception as e:
raise e
if __name__ == "__main__":
pytest.main(["test_baidu.py"])

View File

@ -1,39 +0,0 @@
"""
=================================
Author: Flora Chen
Time: 2021/3/2 21:54
-_- -_- -_- -_- -_- -_- -_- -_-
=================================
"""
from selenium import webdriver
import pytest
from selenium.webdriver.common.by import By
import time
from selenium.webdriver.support.select import Select
def test_login():
driver = webdriver.Chrome()
driver.get("file:///D:/PythonProject/WebUiPy36/login.html")
driver.find_element_by_id("user").send_keys("floratest")
driver.find_element_by_name("password").send_keys("123456")
# 定位-------------select-----------------
driver.find_element(By.XPATH, "//option[text()='AM']").click()
time.sleep(2)
elem = driver.find_element(By.ID, "role")
Select(elem).select_by_index(0)
time.sleep(2)
Select(elem).select_by_value("2")
time.sleep(2)
Select(elem).select_by_visible_text("OM")
# 定位-------------select-----------------
time.sleep(2)
driver.find_element_by_class_name("submit").click()
assert driver.current_url == "http://httpbin.org/post"
if __name__ == "__main__":
pytest.main(["test_login.py"])

@ -1 +0,0 @@
Subproject commit 00f4f8b4f613fcf23ed0279877df893efb76e211

View File

@ -1,84 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
.title{
color: red;
font-size: 30px;
}
</style>
<!-- <script type="text/javascript" src="js/main.js">
</script> -->
<script>
window.onload = function(){
//1、 js定位页面元素
// 通过id获取元素
var b = document.getElementById('box')
console.log(b)
// 通过class属性定位元素
var b1 = document.getElementsByClassName('box1')
console.log(b1)
// 通过css选择器去定位元素
var b3 = document.querySelector('.box1 a')
// 2、js修改元素的文本
// // innerText
// document.querySelector('#box').innerText = 'python666'
// document.querySelector('#box').innerText = '<h1>python123</h1>'
// innerHTML
document.querySelector('#box').innerHTML = '<h1>python123</h1>'
// 3、js修改元素的属性
document.querySelector('.box1 a').href = 'http://www.baidu.com'
// 4、js修改元素的class属性
document.querySelector('.box1 a').className = 'title'
// 5、js修改style属性的值
document.querySelector('#box').style.color = 'yellow'
// 注意点font-size 这种多个单词组成的样式,需要写成小驼峰命令的风格-->fontSize
document.querySelector('#box').style.fontSize = '40px'
// 6、给元素绑定事件
document.querySelector('#btn').onclick = function(){
document.querySelector('#box').style.color = 'blue'
alert('python666')
}
// 7、window.onload事件 会等到页面文档加载关闭之后才会执行。
}
</script>
</head>
<body>
<div id="box" class="box1" style="color: aqua;"></div>
<div class="box1">
<a href="">百度</a>
</div>
<button id="btn">按钮</button>
</body>
</html>

View File

@ -1,59 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 整个页面的所有的内容都放到一个根节点里面 -->
<!-- <ul>
<li id='n' >姓名:</li>
<li id='a'>年龄:</li>
<li id='s'>性别:</li>
</ul> -->
<h1>{{desc}}</h1>
<ul>
<li>姓名:{{info.name}}</li>
<li>年龄:{{info.age}}</li>
<li>性别:{{info.sex}}</li>
</ul>
</div>
<script type="text/javascript">
// 1、使用原生的js 往页面中填充数据
// data = {
// name: "木森",
// age: 18,
// sex: "男"
// }
// //
// document.getElementById('n').innerHTML = document.getElementById('n').innerText+data.name
// document.getElementById('a').innerHTML = document.getElementById('a').innerText+data.age
// document.getElementById('s').innerHTML = document.getElementById('s').innerText+data.sex
//2、使用vue往页面中填充数据
// 初始化一个vue对象
var vm = new Vue({
// el 用来指定挂载对象
el: "#app",
// data 用来保存数据的
data: {
// 个人信息的数据
info: {
name: "木森",
age: 19,
sex: "男"
},
desc:"这个是标题"
}
})
</script>
</body>
</html>

View File

@ -1,56 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<p>{{msg}}</p>
<p v-text="msg"></p>
<p v-html="desc"></p>
<p v-pre>显示的内容:{{msg1}}</p>
<a v-bind:href="url">点击跳转到我的主页</a>
<a :href="url2">淘宝</a>
</div>
<script type="text/javascript">
/*
一、html的文本填充
1、插值表达式:{{ 值}}
2、v-text指令往元素中填充文本
3、v-html指令往元素中填充html
4、v-pre指定 显示原始的数据格式
二、元素的属性绑定v-bind
v-bind 可以简写 :
*/
var vm = new Vue({
el: "#app",
data: {
msg: "hello 木森",
age: 18,
desc: '<h1>musen<\h1>',
url: "http://www.baidu.com",
url2: "http://www.taobao.com"
},
})
</script>
</body>
</html>

View File

@ -1,71 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 数据单向绑定把data中的数据绑定到页面的元素中 -->
<!-- 数值A: <input type="text" name="a" :value="a">
<br>
数值B: <input type="text" name="b" :value="b"> -->
<!-- 数据双向绑定 -->
数值A: <input type="text" name="a" v-model.number="a">
<br>
数值B: <input type="text" name="b" v-model.number="b">
<br>
<br>
<!-- <button type="button" v-on:click="countNumber()">计算</button> -->
<button type="button" @click="countNumber()">计算</button>
<h5>结果:{{c}}</h5>
</div>
<script type="text/javascript">
/*
1、事件绑定v-on
v-on可以简写为@
2、数据双向绑定v-model (绑定的是表单元素的value)
双向绑定,用户输入的数据默认或当成字符串处理
3、双向绑定时表单输入内容数据的转换表单修饰符
.lazyinput数据输入完之后出发
.number:自动把输入的数字转换为数值类型
.trim去除首尾的空白字符
*/
var vm = new Vue({
// 指定vue挂载的根节点
el: "#app",
// 页面中的数据
data: {
a: 11,
b: 22,
c: null
},
// 页面操作要使用的函数
methods: {
// shu计算的方法
countNumber: function() {
this.c = this.a + this.b
}
}
})
</script>
</body>
</html>

View File

@ -1,48 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<div v-if="case_.result=='success'" style="color: chartreuse;">{{case_}}</div>
<div v-else-if="case_.result=='fail'" style="color: #994444">{{case_}}</div>
<div v-else style="color: red;">{{case_}}</div>
<div v-show="false" >9999999999999999</div>
</div>
<script>
/*
v-if
v-else-if
v-else
v-show:控制元素的dispaly属性
*/
var vm = new Vue({
el: '#app',
data: {
case_: {
case_id: 1,
title: "用例001",
result: "error",
show:true
}
}
})
</script>
</body>
</html>

View File

@ -1,77 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<table border="" cellspacing="" cellpadding="">
<tr>
<th>ID</th>
<th>用例名</th>
<th>结果</th>
</tr>
<tr v-for='item in cases'>
<td>{{item.case_id}}</td>
<td>{{item.title}}</td>
<td v-if="item.result=='success'" style="color: green;">{{item.result}}</td>
<td v-else-if="item.result=='fail'" style="color: #5e0000;">{{item.result}}</td>
<td v-else style="color: red;">{{item.result}}</td>
</tr>
<!--遍历数组 -->
<div v-for="(item,index) in cases"> {{item}}-----------{{index}}</div>
<!-- 遍历对象 -->
<div v-for="(value,key) in stus"> {{key}}------{{value}}-----</div>
</table>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
cases: [{
case_id: 1,
title: "用例001",
result: "success"
},
{
case_id: 2,
title: "用例002",
result: "error"
},
{
case_id: 3,
title: "用例003",
result: "fail"
}, {
case_id: 4,
title: "用例004",
result: "success"
}, {
case_id: 5,
title: "用例004",
result: "success"
},
],
stus: {
case_id: 5,
title: "用例004",
result: "success"
}
}
})
</script>
</body>
</html>

View File

@ -1,41 +0,0 @@
window.onload = function() {
//1、 js定位页面元素
// 通过id获取元素
var b = document.getElementById('box')
console.log(b)
// 通过class属性定位元素
var b1 = document.getElementsByClassName('box1')
console.log(b1)
// 通过css选择器去定位元素
var b3 = document.querySelector('.box1 a')
// 2、js修改元素的文本
// // innerText
// document.querySelector('#box').innerText = 'python666'
// document.querySelector('#box').innerText = '<h1>python123</h1>'
// innerHTML
document.querySelector('#box').innerHTML = '<h1>python123</h1>'
// 3、js修改元素的属性
document.querySelector('.box1 a').href = 'http://www.baidu.com'
// 4、js修改元素的class属性
document.querySelector('.box1 a').className = 'title'
// 5、js修改style属性的值
document.querySelector('#box').style.color = 'yellow'
// 注意点font-size 这种多个单词组成的样式,需要写成小驼峰命令的风格-->fontSize
document.querySelector('#box').style.fontSize = '40px'
// 6、给元素绑定事件
document.querySelector('#btn').onclick = function() {
document.querySelector('#box').style.color = 'blue'
alert('python666')
}
}

View File

@ -1,6 +0,0 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6" project-jdk-type="Python SDK" />
</project>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/py08chy.iml" filepath="$PROJECT_DIR$/.idea/py08chy.iml" />
</modules>
</component>
</project>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="Python 3.6" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@ -1,303 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="ea394686-91b0-48fb-b3e9-f98523c6f99c" name="Default Changelist" comment="klll llll.lio&#10;&#10;&#10;&#10;mmmmmmmmm mi,">
<change afterPath="$PROJECT_DIR$/homework/class0521.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/homework/class0524.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/homework/class0526.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/homework/class0528.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/homework/class0531.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/homework/class0602.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/homework/class0604.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/homework/homework0608/__init__.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/homework/homework0608/basepage.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/homework/homework0608/run.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/homework/homework0608/test_demo.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/homework/homework0608/test_demo2.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/homework/homework0611/__init__.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/homework/homework0611/request_work2.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/homework/homework0611/request_work3.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/homework/homework0611/work1.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/homework/homework0611/work2.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/homework/homework0611/work3.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/myddtR/__init__.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/myddtR/myddt.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/myddtR/run.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/myddtR/test_case.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="Python Script" />
</list>
</option>
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="GitSEFilterConfiguration">
<file-type-list>
<filtered-out-file-type name="LOCAL_BRANCH" />
<filtered-out-file-type name="REMOTE_BRANCH" />
<filtered-out-file-type name="TAG" />
<filtered-out-file-type name="COMMIT_BY_MESSAGE" />
</file-type-list>
</component>
<component name="ProjectId" id="1shUvWPaAi2NGVhtjNgGqiHBHYM" />
<component name="ProjectLevelVcsManager" settingsEditedManually="true">
<ConfirmationsSetting value="2" id="Add" />
</component>
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
<property name="WebServerToolWindowFactoryState" value="false" />
<property name="com.intellij.ide.scratch.LRUPopupBuilder$1/New Scratch File" value="Python" />
<property name="last_opened_file_path" value="$PROJECT_DIR$/../../0-xianjinyuan/6-TrustieProject/apiautotest" />
<property name="settings.editor.selected.configurable" value="com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable" />
</component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="D:\1-PythonProject\py08chy\homework\homework0611" />
<recent name="D:\PythonProject\py08chy\homework\homework0608" />
</key>
<key name="MoveFile.RECENT_KEYS">
<recent name="D:\1-PythonProject\py08chy\homework\homework0611" />
<recent name="D:\PythonProject\py08chy\homework" />
<recent name="D:\PythonProject\py08chy\common" />
<recent name="D:\PythonProject\py08chy\bookmanage" />
</key>
</component>
<component name="RunManager" selected="Python.make_code">
<configuration name="make_code" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="py08chy" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/make_code.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="request_work2 (1)" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="py08chy" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/homework/homework0611" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/homework/homework0611/request_work2.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="request_work3" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="py08chy" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/homework/homework0611" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/homework/homework0611/request_work3.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="work1" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="py08chy" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/homework/homework0611" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/homework/homework0611/work1.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="work2" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="py08chy" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/homework/homework0611" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/homework/homework0611/work2.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<recent_temporary>
<list>
<item itemvalue="Python.make_code" />
<item itemvalue="Python.work1" />
<item itemvalue="Python.request_work2 (1)" />
<item itemvalue="Python.work2" />
<item itemvalue="Python.request_work3" />
</list>
</recent_temporary>
</component>
<component name="ServiceViewManager">
<option name="viewStates">
<list>
<serviceView>
<treeState>
<expand />
<select />
</treeState>
</serviceView>
</list>
</option>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="SvnConfiguration">
<configuration />
</component>
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="ea394686-91b0-48fb-b3e9-f98523c6f99c" name="Default Changelist" comment="" />
<created>1621324545548</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1621324545548</updated>
<workItem from="1622034779799" duration="30000" />
<workItem from="1622034822095" duration="53000" />
<workItem from="1622034886778" duration="16000" />
<workItem from="1622034912862" duration="74000" />
<workItem from="1622038633971" duration="1054000" />
<workItem from="1622075873308" duration="4829000" />
<workItem from="1622097679205" duration="929000" />
<workItem from="1622121465010" duration="5179000" />
<workItem from="1622126851753" duration="4454000" />
<workItem from="1622203327135" duration="1290000" />
<workItem from="1622293331369" duration="8696000" />
<workItem from="1622437625143" duration="9000" />
<workItem from="1622437701462" duration="9000" />
<workItem from="1622462469978" duration="5964000" />
<workItem from="1622508939572" duration="241000" />
<workItem from="1622519038434" duration="18000" />
<workItem from="1622552471957" duration="954000" />
<workItem from="1622553495846" duration="6645000" />
<workItem from="1622635384229" duration="1148000" />
<workItem from="1622639528457" duration="4258000" />
<workItem from="1622684049017" duration="69000" />
<workItem from="1622685167381" duration="2000" />
<workItem from="1622705218045" duration="171000" />
<workItem from="1622726067341" duration="7494000" />
<workItem from="1622782794881" duration="35000" />
<workItem from="1622808086764" duration="2157000" />
<workItem from="1622898255899" duration="7999000" />
<workItem from="1623031764486" duration="593000" />
<workItem from="1623056534942" duration="43000" />
<workItem from="1623067309933" duration="1309000" />
<workItem from="1623117107318" duration="595000" />
<workItem from="1623160444099" duration="6935000" />
<workItem from="1623167515173" duration="151000" />
<workItem from="1623240133364" duration="1740000" />
<workItem from="1623296320827" duration="16000" />
<workItem from="1623337921803" duration="2106000" />
<workItem from="1623340059459" duration="2918000" />
<workItem from="1623373476621" duration="109000" />
<workItem from="1623377374627" duration="610000" />
<workItem from="1623766655591" duration="9671000" />
<workItem from="1623805060974" duration="5015000" />
<workItem from="1623844863916" duration="438000" />
<workItem from="1623891684266" duration="15000" />
<workItem from="1624496105541" duration="2667000" />
<workItem from="1625151336162" duration="42000" />
<workItem from="1625151403225" duration="3189000" />
<workItem from="1625186907753" duration="10000" />
</task>
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
<component name="VcsManagerConfiguration">
<ignored-roots>
<path value="$PROJECT_DIR$/py08chy" />
</ignored-roots>
</component>
<component name="com.intellij.coverage.CoverageDataManagerImpl">
<SUITE FILE_PATH="coverage/py08chy$request_work2__1_.coverage" NAME="request_work2 (1) Coverage Results" MODIFIED="1623810349437" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/homework/homework0611" />
<SUITE FILE_PATH="coverage/py08chy$class0531.coverage" NAME="class0531 Coverage Results" MODIFIED="1622635904116" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/homework" />
<SUITE FILE_PATH="coverage/py08chy$work2.coverage" NAME="work2 Coverage Results" MODIFIED="1623810345962" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/homework/homework0611" />
<SUITE FILE_PATH="coverage/py08chy$class0528.coverage" NAME="class0528 Coverage Results" MODIFIED="1622463636257" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/homework" />
<SUITE FILE_PATH="coverage/py08chy$Unittests_for_test_demo_TestDemo_test_login.coverage" NAME="Unittests for test_demo.TestDemo.test_login Coverage Results" MODIFIED="1623164859337" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/homework/homework0608" />
<SUITE FILE_PATH="coverage/py08chy$class0604.coverage" NAME="class0604 Coverage Results" MODIFIED="1622906478953" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/homework" />
<SUITE FILE_PATH="coverage/py08chy$work3.coverage" NAME="work3 Coverage Results" MODIFIED="1623809867450" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/homework/homework0611" />
<SUITE FILE_PATH="coverage/py08chy$make_code.coverage" NAME="make_code Coverage Results" MODIFIED="1624501521974" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
<SUITE FILE_PATH="coverage/py08chy$work1.coverage" NAME="work1 Coverage Results" MODIFIED="1623810387029" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/homework/homework0611" />
<SUITE FILE_PATH="coverage/py08chy$class0602.coverage" NAME="class0602 Coverage Results" MODIFIED="1622733518948" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/homework" />
<SUITE FILE_PATH="coverage/py08chy$scratch.coverage" NAME="scratch Coverage Results" MODIFIED="1623767776471" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$APPLICATION_CONFIG_DIR$/scratches" />
<SUITE FILE_PATH="coverage/py08chy$Unittests_in_test_demo_py.coverage" NAME="Unittests in test_demo.py Coverage Results" MODIFIED="1623165227568" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/homework/homework0608" />
<SUITE FILE_PATH="coverage/py08chy$run.coverage" NAME="run Coverage Results" MODIFIED="1623167594090" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/homework/homework0608" />
<SUITE FILE_PATH="coverage/py08chy$reque.coverage" NAME="reque Coverage Results" MODIFIED="1623772151611" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$APPLICATION_CONFIG_DIR$/scratches" />
<SUITE FILE_PATH="coverage/py08chy$client__2_.coverage" NAME="client (2) Coverage Results" MODIFIED="1623805690210" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/homework/homework0611" />
<SUITE FILE_PATH="coverage/py08chy$request_work3.coverage" NAME="request_work3 Coverage Results" MODIFIED="1623810251102" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/homework/homework0611" />
<SUITE FILE_PATH="coverage/py08chy$class0526.coverage" NAME="class0526 Coverage Results" MODIFIED="1622132329295" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/homework" />
<SUITE FILE_PATH="coverage/py08chy$server.coverage" NAME="server Coverage Results" MODIFIED="1623773392357" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$APPLICATION_CONFIG_DIR$/scratches" />
<SUITE FILE_PATH="coverage/py08chy$client__1_.coverage" NAME="client (1) Coverage Results" MODIFIED="1623771109813" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$APPLICATION_CONFIG_DIR$/scratches" />
</component>
</project>

View File

@ -1,7 +0,0 @@
"""
======================================
Author: Flora.Chen
Time: 2021/5/20 22:30
~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~
======================================
"""

View File

@ -1,219 +0,0 @@
# -*- coding: utf-8 -*-
"""
===============================
@Time : 2021/5/18 16:39
@Author : flora.chen
@FileName: bookmanager.py
@Software: PyCharm
===============================
"""
from common.handle_mysql import MysqlDB
db = MysqlDB(host="localhost", database="bookmanage", user="root", pwd="root")
class BookManage:
"""
图书管理系统
"""
@staticmethod
def print_menu():
"""
菜单打印
:return:
"""
print("---------------------菜单-------------------------")
print("[1]: 添加图书")
print("[2]: 修改图书")
print("[3]: 删除图书")
print("[4]: 查询图书")
print("[5]: 图书列表")
print("[6]: 出借图书")
print("[7]: 归还图书")
print("[8]: 退出")
def add_book(self):
"""
[1]: 添加图书
:return:
"""
print("****************添加图书****************")
name = input("请输入书名:")
position = input("请输入图书位置:")
if name and position:
db.update("insert into books(name, position) value ('{}', '{}');".format(name, position))
print("图书添加成功")
else:
print("书名或者图书位置不能为空,请重新输入!")
num = input("继续添加请输入1 回车退回主菜单")
if num == "1":
self.add_book()
def update_book(self):
"""
[2]: 修改图书
:return:
"""
print("****************修改图书****************")
book_id = input("请输入需要修改的图书ID")
result = db.query("select * from books where id={};".format(book_id), one=True)
if result:
print("当前数据为:{}".format(result))
name = input("重新输入书名,不修改输入回车:") or result["name"]
position = input("重新输入位置,不修改输入回车:") or result["position"]
db.update("update books set name='{}', position='{}' where id={};".format(name, position, book_id))
print("修改成功")
else:
print("您输入的图书ID不存在请重新输入~")
num = input("继续修改请输入1 回车退回主菜单")
if num == "1":
self.update_book()
def delete_book(self):
"""
[3]: 删除图书
:return:
"""
print("****************删除图书****************")
book_id = input("请输入需要修改的图书ID")
result = db.query("select * from books where id={};".format(book_id), one=True)
if result:
print("当前数据为:{}".format(result))
confirm_num = input("确定需要删除这本书吗确认请按1取消请按2")
if confirm_num == "1":
db.update("delete from books where id={};".format(book_id))
print("删除成功")
else:
print("已确认不删除该书籍~")
else:
print("系统中未找到该书籍!")
num = input("继续删除请输入1 回车退回主菜单")
if num == "1":
self.delete_book()
def query_book(self):
"""
[4]: 查询图书
:return:
"""
print("****************查询图书****************")
name = input("请输入您要查询的图书名称(模糊匹配):")
if name:
result = db.query("select * from books where name like '%{}%';".format(name))
if result:
print("当前查询到如下书籍信息:{}".format(result))
else:
print("未查询到相关书籍信息~")
else:
print("书名不能为空!")
num = input("继续查询请输入1 回车退回主菜单")
if num == "1":
self.query_book()
def book_list(self):
"""
[5]: 图书列表
:return:
"""
print("****************图书列表****************")
result = db.query("select * from books;")
for i in result:
print("编号:{} 书籍名:{} 位置:{} 状态:{} 借阅人:{}".format(i["id"], i["name"], i["position"], i["status"],
i["borrower"]))
def borrow_book(self):
"""
[6]: 出借图书
:return:
"""
print("****************出借图书****************")
book_id = input("请输入需要借阅的图书ID")
result = db.query("select * from books where id={};".format(book_id), one=True)
if result:
if result["status"] == "出借":
print("抱歉,该书已经借出!")
else:
while True:
borrower = input("请输入借阅者的名字:")
if borrower:
db.update("update books set borrower='{}' where id={};".format(borrower, book_id))
db.update("update books set status='出借' where id={};".format(book_id))
print("图书借阅成功~")
break
else:
print("借阅者的名字不能为空, 请重新输入")
else:
print("未查询到相关书籍信息~")
num = input("继续借阅请输入1 回车退回主菜单")
if num == "1":
self.borrow_book()
def back_book(self):
"""
[7]: 归还图书
:return:
"""
print("****************归还图书****************")
book_id = input("请输入需要归还的图书ID")
result = db.query("select * from books where id={};".format(book_id), one=True)
if result:
if result["status"] == "在库":
print("该书是在库状态,请确认图书编号是否正确!")
else:
db.update("update books set status='在库' where id={};".format(book_id))
db.update("update books set borrower='' where id={};".format(book_id))
print("书籍归还成功~")
else:
print("未查询到相关书籍信息~")
num = input("继续归还书籍请输入1 回车退回主菜单")
if num == "1":
self.borrow_book()
def quit(self):
"""
[8]: 退出
:return:
"""
print("****************退出****************")
db.close()
def main(self):
"""
程序运行的流程控制
:return:
"""
print("---------------欢迎进入图书管理系统----------------")
while True:
self.print_menu()
num = input("请输入选项:")
if num == "1":
self.add_book()
elif num == "2":
self.update_book()
elif num == "3":
self.delete_book()
elif num == "4":
self.query_book()
elif num == "5":
self.book_list()
elif num == "6":
self.borrow_book()
elif num == "7":
self.back_book()
elif num == "8":
self.quit()
break
else:
print("您的输入有误~ 请按照菜单提示输入,谢谢!")
if __name__ == "__main__":
book = BookManage()
book.main()

View File

@ -1,7 +0,0 @@
"""
======================================
Author: Flora.Chen
Time: 2021/5/20 22:30
~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~
======================================
"""

View File

@ -1,120 +0,0 @@
"""
============================
Author:柠檬班-木森
Time:2021/6/3 13:42
E-mail:3247119728@qq.com
Company:湖南零檬信息技术有限公司
=======
"""
import unittest
class BaseCase(type):
"""
定义的用例类时只要指定该类作为元类会自动化根据用例类中定义的cases属性中的用例数据来动态的生成测试用例
"""
def __new__(cls, name, bases, attrs, *args, **kwargs):
"""定义类时,动态的给类添加用例方法"""
# 1、获取类的cases属性
cases = attrs.get('cases')
# 2、创建类
new_cls = super().__new__(cls, name, bases, attrs)
# 3、遍历类的cases属性值用例数据
for test_name, datas in list(cases.items()):
# 4、获取类里面定义的用例方法
func = attrs.get(test_name)
for index, case in enumerate(datas):
# 5、传入原用例名和数据的索引值创建一个新的用例名
new_test_name = cls._create_test_name(index, test_name)
# 6、创建用例方法的文档字符串描述第6步只是为了在测试报告中显示用例的标题
if isinstance(case, dict) and case.get("title"):
# 6.1如果每条用例数据是一个字典那么就获取用例数据中的title字段对应的值
test_desc = case.get("title")
elif hasattr(case, 'title'):
# 6.2如果用例数据有title属性那么就获取title属性对应的值
test_desc = case.title
else:
# 6.3上述条件都不成立,则获取原方法中的文档字符串注释
test_desc = func.__doc__
# 7、对用例类中定义的方法的文档字符串注释修改传入用例参数
new_func = cls._update_func(case, test_desc, func)
# 8、将创建出来的方法(用例),动态添加到类中
setattr(new_cls, new_test_name, new_func)
delattr(new_cls, test_name)
return new_cls
@staticmethod
def _create_test_name(index, name):
"""
:param index: 用例数据的索引值
:param name: 测试类中定义的方法名称
:return:
"""
if index + 1 < 10:
test_name = name + "_0" + str(index + 1)
else:
test_name = name + "_" + str(index + 1)
return test_name
@staticmethod
def _update_func(case, test_desc, func):
"""
1定义一个嵌套函数wrapper
2修改wrapper的文档字符串注释
3返回wrapper这个函数外部接收到wrapper时会把wrapper设置为测试类的用例方法
unittest在执行setattr动态添加的用例时实际上是执行这里的wrapper,
在wrapper中执行的最初类中定义的用例方法并传入用例数据
:param case: 用例数据
:param test_desc: 用例的文档字符串注释会在显示在测试报告中
:param func: 类里面定义的用例方法
:return:
"""
# 1、定义一个函数wrapper
def wrapper(self, *args, **kwargs):
# 调用类中定义的原用例方法在调用的时候传入用例数据case
return func(self, case, *args, **kwargs)
# 2、修改wrapper的文档字符串注释
wrapper.__doc__ = test_desc
# 3、返回内层的嵌套函数wrapper
return wrapper
# -------------------------------------下面为测试代码-------------------------------------------------------
class TestDome(unittest.TestCase, metaclass=BaseCase):
"""
测试用例类
指定上面的定义元类来创建测试类可以替代ddt所实现的功能
用例数据只要定义在测试类中的cases属性中每个用例方法的数据在cases中通过方法名来指定即可
"""
cases = {
# 定义test_login方法的用例数据
'test_login': [
{'title': "登录用例1", "data": 11},
{'title': "登录用例2", "data": 11},
{'title': "登录用例3", "data": 11}],
# 定义test_register方法的用例数据
'test_register': [
{'title': "注册用例1", "data": 22},
{'title': "注册用例2", "data": 22},
{'title': "注册用例3", "data": 22}],
}
def test_login(self, case):
# 用例方法中定义一个参数,用例介绍用例的数据
assert case['data'] == 11
def test_register(self, case):
assert case['data'] == 22
if __name__ == '__main__':
import unittestreport
suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestDome)
unittestreport.TestRunner(suite).run()

View File

@ -1,76 +0,0 @@
# -*- coding: utf-8 -*-
"""
===============================
@Time : 2021/5/18 15:56
@Author : flora.chen
@FileName: handle_mysql.py
@Software: PyCharm
===============================
"""
import pymysql
class MysqlDB:
"""
操作mysql数据库
"""
def __init__(self, host, user, pwd, database=None, port=3306):
"""
初始化数据库链接
:param host: 主机地址
:param user: 用户名
:param pwd: 密码
:param database: 数据库名称默认为空
:param port: 端口号默认3306
"""
self.conn = pymysql.connect(
host=host,
user=user,
password=pwd,
database=database,
port=port,
cursorclass=pymysql.cursors.DictCursor
)
# 创建一个游标对象
self.cur = self.conn.cursor()
def update(self, sql):
"""
进行增删改操作
:param sql: 需要执行的SQL
:return:
"""
# 执行SQL
result = self.cur.execute(sql)
# 提交事务
self.conn.commit()
return result
def query(self, sql, one=False):
"""
进行查询操作
:param one: 判断是要返回所有查询数据还是第一条默认是所有
:param sql: 要执行的SQL
:return:
"""
# 执行SQL
self.cur.execute(sql)
if one:
return self.cur.fetchone()
else:
return self.cur.fetchall()
def close(self):
"""
断开游标关闭数据库连接
:return:
"""
self.cur.close()
self.conn.close()
if __name__ == "__main__":
db = MysqlDB(host="localhost", user="root", pwd="root")
print(db.query("select * from bookmanage.books"))
# db.update("insert into bookmanage.books(name, position) value ('python从入门到放弃', 'A-1-1');")

View File

@ -1,7 +0,0 @@
"""
======================================
Author: Flora.Chen
Time: 2021/5/20 22:30
~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~
======================================
"""

View File

@ -1,46 +0,0 @@
# -*- coding: utf-8 -*-
"""
===============================
@Time : 2021/5/20 10:58
@Author : flora.chen
@FileName: class0519.py
@Software: PyCharm
===============================
"""
"""
2通过列表推导式完成下面数据类型转换
现在有以下数据 li1 = ["{'a':11,'b':2}","[11,22,33,44]"]
需要转换为以下格式 li1 = [{'a':11,'b':2},[11,22,33,44]]
"""
li1 = ["{'a':11,'b':2}", "[11,22,33,44]"]
li2 = [eval(i) for i in li1]
print(li2)
"""
Names=['python','java','php','c','c++','django','unittest','pytest','pymysql'],请通过列表推导式获取names中字符串长度大于4的元素
"""
Names = ['python', 'java', 'php', 'c', 'c++', 'django', 'unittest', 'pytest', 'pymysql']
name = [i for i in Names if len(i) > 4]
print(name)
"""
使用字典推倒是将下面字符串格式的数据改成字典类型的数据
cook_str='BIDUPSID=D0727533D7147B7;PSTM=1530348042; BAIDUID=B1005C9BC2EB28; sugstore=0;__cfduid=d0a13458f8ac2a;BD_UPN=12314353;ispeed_lsm=2;BDORZ=B490B5EBF6F3CD402'
转换后的结果
{'BIDUPSID': 'D0727533D7147B7', 'PSTM': '1530348042', ' BAIDUID': 'B1005C9BC2EB28', ' sugstore': '0', '__cfduid': 'd0a13458f8ac2a', 'BD_UPN': '12314353', 'ispeed_lsm': '2', 'BDORZ': 'B490B5EBF6F3CD402'}
"""
cook_str = 'BIDUPSID=D0727533D7147B7;PSTM=1530348042;BAIDUID=B1005C9BC2EB28; sugstore=0;__cfduid=d0a13458f8ac2a;BD_UPN=12314353;ispeed_lsm=2;BDORZ=B490B5EBF6F3CD402'
cook_dic = {i.split("=")[0]: i.split("=")[1] for i in cook_str.split(";")}
print(cook_dic)

View File

@ -1,90 +0,0 @@
"""
======================================
Author: Flora.Chen
Time: 2021/5/22 12:02
~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~
======================================
"""
"""
2现在有一个列表 li = [11,21,4,55,6,67,123,54,66,9,90,56,34,22],
请将 大于5的数据过滤出来然后除以2取余数结果放到一个生成器中
"""
# 生成器函数
def generate_num():
li = [11, 21, 4, 55, 6, 67, 123, 54, 66, 9, 90, 56, 34, 22]
for i in li:
if i > 5:
yield i % 2
# 创建一个生成器对象
n = generate_num()
# 获取生成器中的数据放置到列表中
result = [j for j in n]
# 打印列表
print(result)
# 生成器表达式
li = [11, 21, 4, 55, 6, 67, 123, 54, 66, 9, 90, 56, 34, 22]
nums = (i % 2 for i in li if i > 5)
print(nums)
"""
3定义一个可以使用send传入域名自动生成一个在前面加上http://在后面加上路径/user/login的url地址
生成器最多可以生成5个url,生成5条数据之后再去生成则报错StopIteration
使用案例
# 例如:
res = g.send('www.baidu.com')
# 生成数据res为http://www.baidu.com/user/logim'
"""
def generate_url():
url = "/user/login"
host = "http://"
whole_url = host + url
for i in range(5):
print(f"{i + 1}条数据~")
s = yield whole_url
whole_url = host + s + url
g = generate_url()
g.__next__()
print(g.send("www.baidu.com"))
print(g.send("www.ketangpai.com"))
print(g.send("www.lenmon.com"))
print(g.send("www.tecent.com"))
# print(g.send("www.flora.com"))
"""
4面试扩展题
有一个正整数列表(数据是无序的,并且允许有相等的整数存在),
编写一个能实现下列功能的函数传入列表array,和正整数X返回下面要求的三个数据
def func(array, x)
'''逻辑代码'''
return count, li, new_array
1统计并返回在列表中,比正整数x大的数有几个(相同的数只计算一次)并返回-----返回值中的的count
2计算列表中比正整数X小的所有偶数并返回 -----------返回值中的li
3将列表中比正整数X小的偶数去掉,未去掉的数添加到新列表中并返回-------返回值中的new_array
"""
def func(array, x):
# 统计并返回在列表中,比正整数x大的数有几个(相同的数只计算一次)
count = len([i for i in set(array) if i > x])
# 计算列表中比正整数X小的所有偶数并返回
li = [i for i in array if i < x and i % 2 == 0]
# 将列表中比正整数X小的偶数去掉,未去掉的数添加到新列表中
new_array = [i for i in array if i not in li]
return count, li, new_array
li = [1, 2, 2, 3, 4, 5, 5, 6, 7, 7, 8, 8]
res = func(li, 5)
print(res)

View File

@ -1,59 +0,0 @@
"""
======================================
Author: Flora.Chen
Time: 2021/5/25 20:40
~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~
======================================
"""
def work1(height, count):
"""
2 一个球从100米高度自由落下每次落地后反跳回原高度的一半再落下
求它在第10次落地时共经过多少米请用递归实现
:param height:
:param count:
:return:
"""
if count == 1:
return height
else:
return work1(height / 2, count - 1) + (height + height / 2)
print(work1(100, 10))
"""
3问题小明有一对刚出生的兔子兔子的成长期为2个月从第三个月开始每个月都生一对小兔子
小兔子从第三个月开始每个月也会生一对兔子假如兔子都不死问n个月后的兔子总数为多少请用递归实现意味着生长期为2个月
"""
def work2(month):
if month == 1 or month == 2:
return 1
else:
return work2(month - 1) + work2(month - 2)
print("兔子的个数:{}".format(work2(5) * 2))
"""
4有一个列表 li2 = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],
请用代码处理成下面的格式
li4 = [[1,2,3],[4,5,6],[7,8,9],[10,11,12],[13,14,15]]
"""
def work3(n):
li2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
li4 = []
for j in range(int(len(li2) / n)):
new_li = []
for i in range(n):
new_li.append(li2[j * n + i])
li4.append(new_li)
return li4
print(work3(3))

View File

@ -1,109 +0,0 @@
"""
======================================
Author: Flora.Chen
Time: 2021/5/27 8:38
~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~
======================================
"""
import time
"""
2实现一个重运行的装饰器可以用来装饰任何一个功能函数只要被装饰的函数执行出现AssertionError则重新调用该函数
同一个函数最多重运行三次
"""
def retry(count=3):
def wrapper(func):
def inner_wrapper(*args, **kwargs):
for i in range(count):
try:
res = func(*args, **kwargs)
return res
except AssertionError as err:
print(f"{i + 1}失败")
raise AssertionError
return inner_wrapper
return wrapper
@retry(3)
def test_case():
assert 1 == 1
test_case()
"""
3编写装饰器为多个函数加上登录认证的功能设置个默认的初始账号密码
要求登录成功一次后续的函数都无需再输入用户名和密码
"""
login_status = False
def login(func):
def wrapper(*args, **kwargs):
global login_status
if login_status:
print("已经登录过了,无需再登录。")
res = func(*args, **kwargs)
return res
else:
username = input("请输入用户名:")
password = input("请输入密码:")
if all([username, password]):
print("用户名密码正确,登录成功")
res = func(*args, **kwargs)
login_status = True
return res
else:
print("用户名密码错误,登录失败")
return wrapper
@login
def search():
print("查询成功")
@login
def update():
print("更新成功")
search()
update()
"""
4请设计一个装饰器接收一个int类型的参数number可以用来装饰任何的函数
如果函数运行的时间大于number则打印出函数名和函数的运行时间
"""
def count_time(num: int):
def wrapper(func):
def inner_wrapper(*args, **kwargs):
# 获取开始执行的时间
s_time = time.time()
func(*args, **kwargs)
# 获取结束执行的时间
e_time = time.time()
count = int(e_time - s_time)
if count > num:
print(f"函数运行的时间:{count} 大于num{num}")
return inner_wrapper
return wrapper
@count_time(4)
def work4():
time.sleep(5)
work4()

View File

@ -1,130 +0,0 @@
"""
======================================
Author: Flora.Chen
Time: 2021/5/29 21:47
~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~
======================================
"""
import random
import time
print("------------------第2题-------------------------")
"""
第2题 通过装饰器实现单例模式只要任意一个类使用该装饰器装饰
那么就会变成一个单例模式的类(面试真题)
"""
def single_object(cls):
def wrapper(*args, **kwargs):
if not hasattr(cls, "__instance"):
cls.__instance = cls(*args, **kwargs)
else:
cls.__instance.__init__(*args, **kwargs)
return cls.__instance
return wrapper
def single_object2(cls):
dic = {}
def wrapper(*args, **kwargs):
# 判断该类是否创建对象
if dic.get(cls):
return dic[cls]
else:
# 保存到dic这个字典中
dic[cls] = cls(*args, **kwargs)
return dic[cls]
@single_object
class TestCase:
def __init__(self, a, b):
self.a = a
self.b = b
t = TestCase(1, 2)
print(t, t.a)
t2 = TestCase(3, 4)
print(t2, t2.a)
"""
第3题请实现一个类前五次创建对象每次都可以返回一个新的对象
第六次开始每次创建都随机返回前5个对象中的一个
"""
print("------------------第3题-------------------------")
import random
class TestWork:
# count = 0
objs = []
def __new__(cls, *args, **kwargs):
if len(cls.objs) < 5:
# if cls.count < 5:
obj = super().__new__(cls)
cls.objs.append(obj)
# cls.count += 1
return obj
else:
return random.choice(cls.objs)
# return cls.objs[random.randint(0, 4)]
print("-----------前面五次---------------")
test1 = TestWork()
print(test1)
test2 = TestWork()
print(test2)
test3 = TestWork()
print(test3)
test4 = TestWork()
print(test4)
test5 = TestWork()
print(test5)
print("-----------第六次---------------")
test6 = TestWork()
print(test6)
"""
第4题通过类实现一个装饰器既可以装饰函数又可以装饰器类不管函数和类需不需要传参都可以装饰
"""
print("------------------第4题-------------------------")
class ClassDecorator:
def __init__(self, func_cls):
self.func_cls = func_cls
def __call__(self, *args, **kwargs):
current_time = time.strftime("%H:%M:%S")
print(f"当前时间:{current_time}")
return self.func_cls(*args, **kwargs)
@ClassDecorator
class Case:
@staticmethod
def get_time():
current_date = time.strftime("%Y-%m-%d")
print(f"当前日期:{current_date}")
@ClassDecorator
def work4(a, b):
return a + b
c = Case()
print(c)
c.get_time()
res = work4(1, 2)
print(res)

View File

@ -1,115 +0,0 @@
"""
======================================
Projectpy08chy
Fileclass0531.py
IDEPyCharm
Author: Flora.Chen
Time: 2021/5/31 22:25
======================================
"""
"""
第一题整理上课的笔记
"""
"""
第二题自定义一个列表类型实现对象可以之间可以 使用 - 来进行操作
# 要求:如果一个对象减去另一个对象,则把和被减对象中一样的数据给删除掉
# 如下:
li1 = MyList([11, 22, 33,22, 44])
li2 = MyList([1, 22])
res = li1 - li2
# res 打印的结果为[11,33,44]
"""
class MyList:
def __init__(self, value):
self.value = value
def __sub__(self, other):
return [i for i in self.value if i not in other.value]
li1 = MyList([11, 22, 33, 22, 44])
li2 = MyList([1, 22])
res = li1 - li2
print(res)
print("---------------------------------数字25255她3")
"""
第三题自定义一个类
1通过上课的相关知识点对这个类创建的对象进行属性限制对象只能设置这个三个属性 title money data
2通过相关机制对设置的属性类型进行限制title只能设置字符串类型数据
money设置为int类型数据 data可以设置为任意类型
3通过相关机制实现data 属性不能进行删除
4当money设置的值少于0时确保查询出来的值为0
"""
class Test:
# 通过上课的相关知识点对这个类创建的对象,进行属性限制,对象只能设置这个三个属性: title money data
__slots__ = ["title", "money", "data"]
def __init__(self, title, money, data):
self.money = money
self.title = title
self.data = data
def __setattr__(self, key, value):
# title只能设置字符串类型数据
if key == "title":
if isinstance(value, str):
super().__setattr__(key, value)
else:
raise ValueError("title只能是字符串类型")
# money设置为int类型数据
elif key == "money":
if isinstance(value, int):
# # 当money设置的值少于0时确保查询出来的值为0
# if value < 0:
# value = 0
super().__setattr__(key, value)
else:
raise ValueError("money只能是int类型")
# data可以设置为任意类型
else:
super().__setattr__(key, value)
def __getattribute__(self, item):
# 先查询出来属性值
if item == "money":
value = super().__getattribute__(item)
# 在判断属性值少于0时确保查询出来的值为0
if value < 0:
value = 0
return value
else:
return super().__getattribute__(item)
def __delattr__(self, item):
if item == "data":
raise AttributeError("data属性不能删除")
else:
super().__delattr__(item)
demo = Test("test", 100, "数据")
print(demo.title, demo.money, demo.data) # 输出test 100 数据
# data可以是任意数据类型
demo = Test("test", 100, 123)
print(demo.title, demo.money, demo.data) # 输出test 100 123
demo = Test("test", 100, 123.1)
print(demo.title, demo.money, demo.data) # 输出test 100 123.1
demo = Test("test", 100, True)
print(demo.title, demo.money, demo.data) # 输出test 100 True
# 设置非字符串类型的title
# demo = Test(1, 100, "数据") # 报错ValueError: title只能是字符串类型
# 设置非int的money
# demo = Test("test", 100.1, "数据") # 报错ValueError: money只能是int类型
# demo = Test("test", "1", "数据") # 报错ValueError: money只能是int类型
# money小于0
demo = Test("test", -1, "数据")
print(demo.title, demo.money, demo.data) # 输出test 0 数据

View File

@ -1,125 +0,0 @@
"""
======================================
Projectpy08chy
Fileclass0602.py
IDEPyCharm
Author: Flora.Chen
Time: 2021/6/3 15:27
======================================
"""
import threading
import time
"""
1整理上课笔记
"""
"""
2一个列表中有100个url地址请设计程序一个程序获取列表中的url地址
使用4个线程去发送这100个请求假设请求每个地址需要0.5请求的代码用time.sleep(0.5)代替
计算出总耗时
"""
from faker import Faker
from threading import Thread
def count_time(func):
def wrapper(*args, **kwargs):
# 获取开始执行的时间
s_time = time.time()
func(*args, **kwargs)
# 获取结束执行的时间
e_time = time.time()
count = int(e_time - s_time)
print("运行时间:{}".format(count))
return wrapper
def generate_url(n):
"""
随机生成指定数量的url地址
:param n: 指定数量
:return:
"""
faker = Faker()
urls = [faker.url() for i in range(n)]
return urls
def request(urls):
"""模拟请求"""
for url in urls:
print(f"线程{threading.current_thread().ident} 请求的地址是:{url}")
time.sleep(0.5)
@count_time
def work1(thread_num, url_num):
"""使用thread_num个线程去发送这url_num个请求"""
# url_num = 100
urls = generate_url(url_num)
# 开线程
threads = []
for i in range(thread_num):
thread = Thread(target=request, args=(urls[int(i * url_num / thread_num):int(url_num / thread_num * (i + 1))],))
threads.append(thread)
print(f"所有的线程:{threads}")
for i in threads:
i.start()
for i in threads:
i.join()
work1(4, 100)
"""
3自定义一个元类可以在创建类的时候自动给类添加class_name,create_time这两个类属性属性值自己随便写一个
"""
class MyClass(type):
"""创建类的时候自动给类添加属性的元类"""
def __new__(cls, *args, **kwargs):
# 创建类
cls = super().__new__(cls, *args, **kwargs)
# 给类动态添加属性
setattr(cls, "class_name", "class_name属性值")
setattr(cls, "create_time", "create_time属性值")
return cls
TestClass1 = MyClass("TestClass1", (object,), {})
print(TestClass1)
print(TestClass1().class_name)
"""
4(面试扩展算法题和上课内容无关不计分可以不交在作业里不是必做题)
有一艘船上有40个人由于触礁出现了漏水现在船上最多只能载20个人需要20个人下船
于是这40个人排成一队根据站位每个人领取了一个编号从1开始到40
然后从1开始到9进行循环报数报数为9的人出列下船一直循环直到船上只剩下20人
示例1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19....40
第一次报到9下船的人编号为91,2,3,...编号为9的人报9
第二次下船的编号为1810的人报1....18的人报9
第三次下船的编号为27 19的人报1....27的人报9
第四次下船编号为36 28的人报1....36的人报9
第五次下船编号为5 37的人报138报2,39报3,40报4....5的人报9
第六次下船编号为15
.....
请问最后那些编号的人下船了
"""
people = [i for i in range(1, 41)]
off_boat = []
on_boat = []
num = 0
while len(people) > 20:
for index, value in enumerate(people):
num += 1
if num % 9 == 0:
value = people[index]
off_boat.append(value)
people = [i for i in people if i not in off_boat]
print(f"留在船上的人:{people}")
print(f"下船的人:{off_boat}")

View File

@ -1,135 +0,0 @@
"""
======================================
Projectpy08chy
Fileclass0604.py
IDEPyCharm
Author: Flora.Chen
Time: 2021/6/5 21:11
======================================
"""
import threading
"""
整理上课笔记
"""
"""
使用队列和线程完成下面要求生产者消费者模式
1用一个队列来存储数据
2定义一个专门生产数据的线程类当队列中数据数量少于50时开始生产数据每次生产200个数据添加到队列中每生产完一轮 暂停1秒
3定义一个专门获取数据的线程类当队列中数据数量大于10时就开始获取,循环获取,每次获取20个当队列中数据数量少于10的时候暂停2秒
4启动程序 创建一个线程生产数据 5个线程获取数据
"""
from queue import Queue
from threading import Thread
import time
# 用一个队列来存储数据
q = Queue()
class GenerateData(Thread):
"""专门生产数据的线程类"""
def run(self) -> None:
"""定义线程对象执行的任务"""
"""当队列中数据数量少于50时开始生产数据每次生产200个数据添加到队列中每生产完一轮 暂停1秒"""
while True:
if q.qsize() < 50:
print(f'队列中还剩{q.qsize()}个数开始生产200个')
for i in range(200):
q.put(i + 1)
time.sleep(1)
print('生产完成休眠1秒')
class GetData(Thread):
"""专门获取数据的线程类"""
def run(self) -> None:
"""定义线程对象执行的任务"""
"""当队列中数据数量大于10时就开始获取,循环获取,每次获取20个。当队列中数据数量少于10的时候暂停2秒"""
while True:
if q.qsize() > 10:
print(f'线程{threading.current_thread().ident}消耗20个')
for i in range(20):
q.get()
else:
print(f'队列中还剩{q.qsize()},线程{threading.current_thread().ident}休眠2秒')
time.sleep(2)
def main():
"""启动程序 创建一个进线程生产数据 5个线程获取数据"""
# 生产数据的线程
generate_data_thread = GenerateData()
# 获取数据的线程
get_data_thread1 = GetData()
get_data_thread2 = GetData()
get_data_thread3 = GetData()
get_data_thread4 = GetData()
get_data_thread5 = GetData()
# 启动线程
generate_data_thread.start()
get_data_thread1.start()
get_data_thread2.start()
get_data_thread3.start()
get_data_thread4.start()
get_data_thread5.start()
# 主线程join子线程
generate_data_thread.join()
get_data_thread1.join()
get_data_thread2.join()
get_data_thread3.join()
get_data_thread4.join()
get_data_thread5.join()
main()
"""
import gevent
import unittest
class TestRunner:
# 线程池实现
def __init__(self):
self.suites = []
def get_suite(self, suite):
# 将测试套件以测试类进行拆分,加入队列中
for item in suite:
if isinstance(item, unittest.TestCase):
self.suites.append(suite)
break
else:
self.get_suite(item)
def run(self, suite):
# 分隔套件
self.get_suite(suite)
result = unittest.TestResult()
gs = [gevent.spawn(sute.run, result) for sute in self.suites]
# for sute in suite:
# g = gevent.spawn(sute.run, result)
# gs.append(g)
[i.join() for i in gs]
for i in gs:
i.join()
print(result)
"""

View File

@ -1,9 +0,0 @@
"""
======================================
Projectpy08chy
File__init__.py.py
IDEPyCharm
Author: Flora.Chen
Time: 2021/6/8 22:54
======================================
"""

View File

@ -1,85 +0,0 @@
"""
============================
Author:柠檬班-木森
Time:2021/6/3 13:42
E-mail:3247119728@qq.com
Company:湖南零檬信息技术有限公司
=======
"""
class BaseCase(type):
"""
定义的用例类时只要指定该类作为元类会自动化根据用例类中定义的cases属性中的用例数据来动态的生成测试用例
"""
def __new__(cls, name, bases, attrs, *args, **kwargs):
"""定义类时,动态的给类添加用例方法"""
# 1、获取类的cases属性
cases = attrs.get('cases')
# 2、创建类
new_cls = super().__new__(cls, name, bases, attrs)
# 3、遍历类的cases属性值用例数据
for test_name, datas in list(cases.items()):
# 4、获取类里面定义的用例方法
func = attrs.get(test_name)
# 遍历用例方法的数据
for index, case in enumerate(datas):
# 5、传入原用例名和数据的索引值创建一个新的用例名
new_test_name = cls._create_test_name(index, test_name)
# 6、创建用例方法的文档字符串描述第6步只是为了在测试报告中显示用例的标题
if isinstance(case, dict) and case.get("title"):
# 6.1如果每条用例数据是一个字典那么就获取用例数据中的title字段对应的值
test_desc = case.get("title")
elif hasattr(case, 'title'):
# 6.2如果用例数据有title属性那么就获取title属性对应的值
test_desc = str(case.title)
else:
# 6.3上述条件都不成立,则获取原方法中的文档字符串注释
test_desc = func.__doc__
# 7、对用例类中定义的方法的文档字符串注释修改传入用例参数
new_func = cls._update_func(case, test_desc, func)
# 8、将创建出来的方法(用例),动态添加到类中
setattr(new_cls, new_test_name, new_func)
delattr(new_cls, test_name)
return new_cls
@staticmethod
def _create_test_name(index, name):
"""
:param index: 用例数据的索引值
:param name: 测试类中定义的方法名称
:return:
"""
if index + 1 < 10:
test_name = name + "_0" + str(index + 1)
else:
test_name = name + "_" + str(index + 1)
return test_name
@staticmethod
def _update_func(case, test_desc, func):
"""
1定义一个嵌套函数wrapper
2修改wrapper的文档字符串注释
3返回wrapper这个函数外部接收到wrapper时会把wrapper设置为测试类的用例方法
unittest在执行setattr动态添加的用例时实际上是执行这里的wrapper,
在wrapper中执行的最初类中定义的用例方法并传入用例数据
:param case: 用例数据
:param test_desc: 用例的文档字符串注释会在显示在测试报告中
:param func: 类里面定义的用例方法
:return:
"""
# 1、定义一个函数wrapper
def wrapper(self, *args, **kwargs):
# 调用类中定义的原用例方法在调用的时候传入用例数据case
return func(self, case, *args, **kwargs)
# 2、修改wrapper的文档字符串注释
wrapper.__doc__ = test_desc
# 3、返回内层的嵌套函数wrapper
return wrapper

View File

@ -1,70 +0,0 @@
"""
======================================
Projectpy08chy
Filerun.py
IDEPyCharm
Author: Flora.Chen
Time: 2021/6/8 22:59
======================================
"""
import unittest
from concurrent.futures import ThreadPoolExecutor
from queue import Queue
from homework.homework0608 import test_demo, test_demo2
"""
# --------------------------- 单线程执行 ---------------------------
suite = unittest.defaultTestLoader.discover(r'D:\PythonProject\py08chy\homework\homework0608')
result = unittest.TestResult()
# 运行用例获取运行结果
res = suite.run(result)
# 打印运行结果
print(res)
"""
"""
# --------------- 一个个用例文件去收集,每个文件作为一个任务 ---------------------------
suite1 = unittest.defaultTestLoader.loadTestsFromModule(test_demo)
suite2 = unittest.defaultTestLoader.loadTestsFromModule(test_demo2)
result = unittest.TestResult()
with ThreadPoolExecutor(4) as ts:
ts.submit(suite1.run, result)
ts.submit(suite2.run, result)
print(result)
"""
suite = unittest.defaultTestLoader.discover(r'D:\PythonProject\py08chy\homework\homework0608')
# --------------以测试类为单位拆分测试套件------------
class TestRunner:
"""
线程池实现
"""
def __init__(self):
self.suites = []
def get_suite(self, suite):
"""将测试套件以测试类进行拆分,加入队列中"""
for item in suite:
if isinstance(item, unittest.TestCase):
self.suites.append(suite)
break
else:
self.get_suite(item)
def run(self, suite, thread_count):
# 分隔套件
self.get_suite(suite)
result = unittest.TestResult()
# 创建线程池
with ThreadPoolExecutor(thread_count) as ts:
for sute in self.suites:
ts.submit(sute.run, result)
return result

View File

@ -1,38 +0,0 @@
"""
======================================
Projectpy08chy
Filetest_demo.py
IDEPyCharm
Author: Flora.Chen
Time: 2021/6/8 22:54
======================================
"""
import time
import unittest
from basepage import BaseCase
class TestDemo(unittest.TestCase, metaclass=BaseCase):
cases = {
"test_login": [
{"title": "登录成功", "data": {"name": "floraachy", "pwd": "123456"}, "expected": 0},
{"title": "登录失败-用户名为空", "data": {"name": "", "pwd": "123456"}, "expected": 0},
{"title": "登录失败-密码为空", "data": {"name": "floraachy", "pwd": ""}, "expected": 0},
{"title": "登录成功", "data": {"name": "floraachy", "pwd": "123456"}, "expected": 0},
{"title": "登录失败-用户名为空", "data": {"name": "", "pwd": "123456"}, "expected": 0},
{"title": "登录失败-密码为空", "data": {"name": "floraachy", "pwd": ""}, "expected": 0},
{"title": "登录成功", "data": {"name": "floraachy", "pwd": "123456"}, "expected": 0},
{"title": "登录失败-用户名为空", "data": {"name": "", "pwd": "123456"}, "expected": 0},
{"title": "登录失败-密码为空", "data": {"name": "floraachy", "pwd": ""}, "expected": 0},
{"title": "登录成功", "data": {"name": "floraachy", "pwd": "123456"}, "expected": 0},
{"title": "登录失败-用户名为空", "data": {"name": "", "pwd": "123456"}, "expected": 0},
{"title": "登录失败-密码为空", "data": {"name": "floraachy", "pwd": ""}, "expected": 0},
{"title": "登录成功", "data": {"name": "floraachy", "pwd": "123456"}, "expected": 0},
{"title": "登录失败-用户名为空", "data": {"name": "", "pwd": "123456"}, "expected": 0},
{"title": "登录失败-密码为空", "data": {"name": "floraachy", "pwd": ""}, "expected": 0}
]
}
def test_login(self, case):
time.sleep(1)
assert case["expected"] == 0

View File

@ -1,38 +0,0 @@
"""
======================================
Projectpy08chy
Filetest_demo.py
IDEPyCharm
Author: Flora.Chen
Time: 2021/6/8 22:54
======================================
"""
import time
import unittest
from basepage import BaseCase
class TestDemo(unittest.TestCase, metaclass=BaseCase):
cases = {
"test_login": [
{"title": "登录成功", "data": {"name": "floraachy", "pwd": "123456"}, "expected": 0},
{"title": "登录失败-用户名为空", "data": {"name": "", "pwd": "123456"}, "expected": 0},
{"title": "登录失败-密码为空", "data": {"name": "floraachy", "pwd": ""}, "expected": 0},
{"title": "登录成功", "data": {"name": "floraachy", "pwd": "123456"}, "expected": 0},
{"title": "登录失败-用户名为空", "data": {"name": "", "pwd": "123456"}, "expected": 0},
{"title": "登录失败-密码为空", "data": {"name": "floraachy", "pwd": ""}, "expected": 0},
{"title": "登录成功", "data": {"name": "floraachy", "pwd": "123456"}, "expected": 0},
{"title": "登录失败-用户名为空", "data": {"name": "", "pwd": "123456"}, "expected": 0},
{"title": "登录失败-密码为空", "data": {"name": "floraachy", "pwd": ""}, "expected": 0},
{"title": "登录成功", "data": {"name": "floraachy", "pwd": "123456"}, "expected": 0},
{"title": "登录失败-用户名为空", "data": {"name": "", "pwd": "123456"}, "expected": 0},
{"title": "登录失败-密码为空", "data": {"name": "floraachy", "pwd": ""}, "expected": 0},
{"title": "登录成功", "data": {"name": "floraachy", "pwd": "123456"}, "expected": 0},
{"title": "登录失败-用户名为空", "data": {"name": "", "pwd": "123456"}, "expected": 0},
{"title": "登录失败-密码为空", "data": {"name": "floraachy", "pwd": ""}, "expected": 0}
]
}
def test_login(self, case):
time.sleep(1)
assert case["expected"] == 0

View File

@ -1,9 +0,0 @@
"""
======================================
Projectpy08chy
File__init__.py.py
IDEPyCharm
Author: Flora.Chen
Time: 2021/6/16 0:15
======================================
"""

View File

@ -1,32 +0,0 @@
import requests
url = "http://127.0.0.1:8899/login"
res = requests.get(url=url)
res2 = requests.post(url=url, data={"name": "flora", "pwd": "123456"})
print(res.text)
print(res2.text)
url = "http://127.0.0.1:8899/report"
res = requests.get(url=url)
res2 = requests.post(url=url, data={"name": "flora1", "pwd": "123456"})
print(res.text)
print(res2.text)
url = "http://127.0.0.1:8899/register"
res = requests.get(url=url)
res2 = requests.post(url=url, data={"name": "flora1s", "pwd": "123456"})
print(res.text)
print(res2.text)
url = "http://127.0.0.1:8899"
res = requests.get(url=url)
res2 = requests.post(url=url, data={"name": "flora1s11", "pwd": "123456"})
print(res.text)
print(res2.text)

View File

@ -1,11 +0,0 @@
import requests
url = "http://127.0.0.1:8899/user/login"
res = requests.get(url=url)
res2 = requests.post(url=url, json={"user": "flora", "pwd": "123456"})
res3 = requests.post(url=url, data={"user": "flor1a", "pwd": "123456"})
res4 = requests.post(url=url, data={"user": "", "pwd": "123456"})
print(res.json())
print(res2.json())
print(res3.json())
print(res4.json())

View File

@ -1,120 +0,0 @@
"""
======================================
Projectpy08chy
Filework1.py
IDEPyCharm
Author: Flora.Chen
Time: 2021/6/16 0:11
======================================
"""
"""
1基本要求使用Socket实现一个可以根据不同访问路径返回不同结果的简易版HTTP服务器
"""
import json
import re
from socket import socket, AF_INET, SOCK_STREAM
from threading import Thread
class HttpServer:
def __init__(self):
# 1. 创建一个TCP套接字
self.server = socket(AF_INET, SOCK_STREAM)
# 2. 绑定IP和端口
self.server.bind(
("127.0.0.1", 8899)
)
# 3. 监听客户端的连接
self.server.listen(100) # 指定最大连接数量100
def main(self):
while True:
# 4. 等待客户端的连接
client_sock, addr = self.server.accept()
Thread(target=self.handler_request, args=(client_sock,)).start()
def handler_request(self, client_sock):
content = ""
while True:
res = client_sock.recv(1024)
if res:
content += res.decode()
if len(res) < 1024:
break
print(f"客户端发送过来的数据:{content}")
# 解析HTTP请求报文
request_data = self.parser_request_data(content)
if request_data["path"] == "/login":
body = login()
# 5. 给客户端回复数据 (返回的数据要以http报文的格式返回)
header = "HTTP/1.1 200 OK\r\n"
header += "Content-Type: text/html;charset=utf-8\r\n"
header += "\r\n\r\n"
data = header + body
elif request_data["path"] == "/report":
body = report()
# 5. 给客户端回复数据 (返回的数据要以http报文的格式返回)
header = "HTTP/1.1 200 OK\r\n"
header += "Content-Type: text/html;charset=utf-8\r\n"
header += "\r\n\r\n"
data = header + body
elif request_data["path"] == "/register":
body = register()
# 5. 给客户端回复数据 (返回的数据要以http报文的格式返回)
header = "HTTP/1.1 200 OK\r\n"
header += "Content-Type: text/html;charset=utf-8\r\n"
header += "\r\n\r\n"
data = header + body
else:
body = "404页面不存在"
# 5. 给客户端回复数据 (返回的数据要以http报文的格式返回)
header = "HTTP/1.1 404 NOT FOUND \r\n"
header += "Content-Type: text/html;charset=utf-8\r\n"
header += "\r\n\r\n"
data = header + body
client_sock.send(data.encode())
client_sock.close()
def parser_request_data(self, content):
"""解析HTTP请求报文"""
# 按行进行分割
lines = content.splitlines()
# 请求方法
method = re.search("^(.+?) ", lines[0]).group(1)
# 请求路径
path = re.search(" (.+?) ", lines[0]).group(1)
# 请求头
headers = content.split("\r\n\r\n")[0].splitlines()[1:]
headers = {item.split(": ")[0]: item.split(": ")[1] for item in headers}
# 请求参数
body = content.split("\r\n\r\n")[1]
params = {}
if headers.get("Content-Type"):
# 判断是否为表单参数
if headers.get("Content-Type") == "application/json":
params["json"] = json.loads(body)
# 判断是否为表单参数
elif headers.get("Content-Type") == "application/X-www-form-urlencoded":
params["data"] = {i.split("=")[0]: i.split("=")[1] for i in body.split("&")}
return dict(method=method, path=path, headers=headers, params=params)
def report():
return open("report.html", "r", encoding="utf-8").read()
def login():
return "登录页面"
def register():
return "注册页面"
if __name__ == '__main__':
HttpServer().main()

View File

@ -1,118 +0,0 @@
"""
======================================
Projectpy08chy
Filework2.py
IDEPyCharm
Author: Flora.Chen
Time: 2021/6/16 0:15
======================================
"""
"""
2扩展要求1实现同一个路径不同的请求方法返回不同的数据
思路提示判断请求的方法返回不同的数据
"""
import json
import re
from socket import socket, AF_INET, SOCK_STREAM
from threading import Thread
class HttpServer:
def __init__(self):
# 1. 创建一个TCP套接字
self.server = socket(AF_INET, SOCK_STREAM)
# 2. 绑定IP和端口
self.server.bind(
("127.0.0.1", 8899)
)
# 3. 监听客户端的连接
self.server.listen(100) # 指定最大连接数量100
def main(self):
while True:
# 4. 等待客户端的连接
client_sock, addr = self.server.accept()
Thread(target=self.handler_request, args=(client_sock,)).start()
def handler_request(self, client_sock):
content = ""
while True:
res = client_sock.recv(1024)
if res:
content += res.decode()
if len(res) < 1024:
break
print(f"客户端发送过来的数据:{content}")
# 解析HTTP请求报文
request_data = self.parser_request_data(content)
method = request_data["method"]
if request_data["path"] == "/login":
if method == "GET":
body = "登录页面"
else:
body = json.dumps(request_data["params"])
# 5. 给客户端回复数据 (返回的数据要以http报文的格式返回)
header = "HTTP/1.1 200 OK\r\n"
header += "Content-Type: text/html;charset=utf-8\r\n"
header += "\r\n\r\n"
data = header + body
elif request_data["path"] == "/report":
if method == "GET":
body = "报告页面"
else:
body = json.dumps(request_data["params"])
# 5. 给客户端回复数据 (返回的数据要以http报文的格式返回)
header = "HTTP/1.1 200 OK\r\n"
header += "Content-Type: text/html;charset=utf-8\r\n"
header += "\r\n\r\n"
data = header + body
elif request_data["path"] == "/register":
if method == "GET":
body = "注册页面"
else:
body = json.dumps(request_data["params"])
# 5. 给客户端回复数据 (返回的数据要以http报文的格式返回)
header = "HTTP/1.1 200 OK\r\n"
header += "Content-Type: text/html;charset=utf-8\r\n"
header += "\r\n\r\n"
data = header + body
else:
body = "404页面不存在"
# 5. 给客户端回复数据 (返回的数据要以http报文的格式返回)
header = "HTTP/1.1 404 NOT FOUND \r\n"
header += "Content-Type: text/html;charset=utf-8\r\n"
header += "\r\n\r\n"
data = header + body
client_sock.send(data.encode())
client_sock.close()
def parser_request_data(self, content):
"""解析HTTP请求报文"""
# 按行进行分割
lines = content.splitlines()
# 请求方法
method = re.search("^(.+?) ", lines[0]).group(1)
# 请求路径
path = re.search(" (.+?) ", lines[0]).group(1)
# 请求头
headers = content.split("\r\n\r\n")[0].splitlines()[1:]
headers = {item.split(": ")[0]: item.split(": ")[1] for item in headers}
# 请求参数
body = content.split("\r\n\r\n")[1]
params = {}
if headers.get("Content-Type"):
# 判断是否为表单参数
if headers.get("Content-Type") == "application/json":
params["json"] = json.loads(body)
# 判断是否为表单参数
elif headers.get("Content-Type") == "application/x-www-form-urlencoded":
params["data"] = {i.split("=")[0]: i.split("=")[1] for i in body.split("&")}
return dict(method=method, path=path, headers=headers, params=params)
if __name__ == '__main__':
HttpServer().main()

View File

@ -1,129 +0,0 @@
"""
======================================
Projectpy08chy
Filework3.py
IDEPyCharm
Author: Flora.Chen
Time: 2021/6/16 0:16
======================================
"""
"""
3扩展要求2再上面的两个要求的基础实现一个求登录接口(不计分做不出来没关系)
接口路径 / user / login
请求方法: post
参数
user: 用户名
pwd: 登录密码
请求参数类型Content - Type: application / json
返回数据示例
账号密码正确返回{'code': 1, 'msg': '登录成功'}
账号密码错误返回{'code': 0, 'msg': '账号密码有误'}
其他异常情况(参数为空, 参数格式错误等等)返回按上述数据格式内容不做限制
思路提示
1从请求数据中提取请求方法请求路径请求头请求参数
2先判断请求路径如果是 / user / login
3在判断请求方法
4在判断请求参数
5校验参数中的账号密码
"""
import json
import re
from socket import socket, AF_INET, SOCK_STREAM
from threading import Thread
class HttpServer:
def __init__(self):
# 1. 创建一个TCP套接字
self.server = socket(AF_INET, SOCK_STREAM)
# 2. 绑定IP和端口
self.server.bind(
("127.0.0.1", 8899)
)
# 3. 监听客户端的连接
self.server.listen(100) # 指定最大连接数量100
def main(self):
while True:
# 4. 等待客户端的连接
client_sock, addr = self.server.accept()
Thread(target=self.handler_request, args=(client_sock,)).start()
def handler_request(self, client_sock):
content = ""
while True:
res = client_sock.recv(1024)
if res:
content += res.decode()
if len(res) <= 1024:
break
print(f"客户端发送过来的数据:{content}")
# 解析HTTP请求报文
request_data = self.parser_request_data(content)
method = request_data["method"]
params = request_data["params"]
if request_data["path"] == "/user/login":
body = json.dumps(login(method, params))
# 5. 给客户端回复数据 (返回的数据要以http报文的格式返回)
header = "HTTP/1.1 200 OK\r\n"
header += "Content-Type: text/html;charset=utf-8\r\n"
header += "\r\n\r\n"
data = header + body
else:
body = "404页面不存在"
# 5. 给客户端回复数据 (返回的数据要以http报文的格式返回)
header = "HTTP/1.1 404 NOT FOUND \r\n"
header += "Content-Type: text/html;charset=utf-8\r\n"
header += "\r\n\r\n"
data = header + body
client_sock.send(data.encode())
client_sock.close()
def parser_request_data(self, content):
"""解析HTTP请求报文"""
# 按行进行分割
lines = content.splitlines()
# 请求方法
method = re.search("^(.+?) ", lines[0]).group(1)
# 请求路径
path = re.search(" (.*?) ", lines[0]).group(1)
# 请求头
headers = content.split("\r\n\r\n")[0].splitlines()[1:]
headers = {item.split(": ")[0]: item.split(": ")[1] for item in headers}
# 请求参数
body = content.split("\r\n\r\n")[1]
params = {}
if headers.get("Content-Type"):
# 判断是否为表单参数
if headers.get("Content-Type") == "application/json":
params["data"] = json.loads(body)
# 判断是否为表单参数
elif headers.get("Content-Type") == "application/x-www-form-urlencoded":
params["data"] = {i.split("=")[0]: i.split("=")[1] for i in body.split("&")}
return dict(method=method, path=path, headers=headers, params=params)
def login(method, params):
user = "flora"
pwd = "123456"
if method == "GET":
body = "登录页面"
else:
if params["data"]["user"] and params["data"]["pwd"]:
if params["data"]["user"] == user and params["data"]["pwd"] == pwd:
body = {'code': 1, 'msg': '登录成功'}
else:
body = {'code': 0, 'msg': '账号密码有误'}
else:
body = {'code': 2, 'msg': 'user或pwd不能为空'}
return body
if __name__ == '__main__':
HttpServer().main()

View File

@ -1,109 +0,0 @@
"""
============================
author:MuSen
time:2019/6/21
E-mail:3247119728@qq.com
============================
"""
from flask import Flask, request, jsonify
from flask_cors import CORS
app = Flask(__name__)
# 测试数据
user_info = {"user": 'python01', 'pwd': 'lemonban'}
project_data = {"code": "1",
"data": [{"title": "前程贷", "id": "1001"},
{"title": "智慧金融", "id": "1002"},
{"title": "生鲜到家", "id": "1003"},
{"title": "柠檬班app", "id": "1004"}],
"msg": "四个项目",
}
# 接口数据
interface_data = {
"1001": {"code": "1",
"data": [{"name": "前程贷登录1001"},
{"name": "前程贷注册1001"}],
"msg": "2个接口", },
"1002": {"code": "1",
"data": [{"name": "智慧-登录1002"},
{"name": "智慧-注册1002"},
{"name": "智慧-贷款1004"}, ],
"msg": "3个接口", },
"1003": {"code": "1",
"data": [{"name": "生鲜-登录1003"},
{"name": "生鲜-注册1003"},
{"name": "生鲜下单1003"}, ],
"msg": "3个接口", },
"1004": {"code": "1",
"data": [{"name": "app登录1004"},
{"name": "app注册1004"},
{"name": "app报名1004"},
{"name": "app缴费1004"},
],
"msg": "4个接口", },
}
# 登录
@app.route('/api/user/login', methods=['post'])
def login():
"""
接口地址http://127.0.0.1:5000/api/user/login
请求方法post
参数 {user:账号,pwd:密码}
参数类型表单 json都支持
返回:登录之后的结果
"""
data = request.form or request.json
# 判断账号,密码是否正确
if user_info.get('user') == data.get('user') and user_info.get('pwd') == data.get('pwd'):
return jsonify({'code': "1", "data": None, "msg": "成功"})
else:
return jsonify({'code': "0", "data": None, "msg": "账号或密码有误"})
# 获取项目列表
@app.route('/api/projects', methods=['get'])
def pro_list():
"""
接口地址http://127.0.0.1:5000/api/projects
请求方法get
参数
返回所有的项目
:return:
"""
return jsonify(project_data)
# 获取接口列表
@app.route('/api/interface', methods=['get'])
def interface():
"""
接口地址http://127.0.0.1:5000/api/interface
请求方法get
参数 id(项目的id)
参数类型查询字符串
返回:该项目的所有接口
"""
inter_id = request.args.get('id')
if inter_id:
res_data = interface_data.get(inter_id)
if res_data:
return jsonify(res_data)
else:
return jsonify({"code": "0", "data": None, "msg": "没有该项目"})
else:
return jsonify({"code": "0", "data": None, "msg": "参数id不能为空"})
if __name__ == '__main__':
cors = CORS(app)
app.run(debug=True)

View File

@ -1,106 +0,0 @@
import json
import re
# import pprint
# import requests
# from common.requests_handler import Request_handler
data = None
url = None
def fiddler_requests():
"""
fiddler请求作为参数通过正则匹配数据处理转成requests请求
:param fiddler_info:
:return:
"""
with open(r"./make_demo.txt", "r", encoding="utf-8") as f:
fiddler_info = f.read()
params_type = {}
headers = {}
if re.search('(.*?) http', fiddler_info) == None:
print("请先复制fiddler请求信息在make_demo.txt文件中")
return
method = re.search('(.*?) http', fiddler_info).group().split(" ")[0]
all_url = re.search(f'{method}(.*?) HTTP/', fiddler_info).group().split(" ")[1]
request_line = fiddler_info.split("\n\n")[0]
request_headers = request_line.split('\n')[1:]
for i in request_headers:
info = "".join(i.split()).split(":")
for header_keys in ["Content-Length", "Host", "Connection", "accept", "User-Agent", "Content-Type", "Origin",
"Referer", "Accept-Encoding", "Cookie", "Accept-Language"]:
if info[0] == header_keys:
headers[info[0]] = info[1]
host_lis = re.compile(r'Host: (.*?)\n', re.DOTALL).findall(fiddler_info)
if host_lis != []:
host = host_lis[0]
url = all_url.split(host)[1]
data_info = re.compile(r'\n\n(.*)', re.DOTALL)
re_data = data_info.findall(fiddler_info)
if re_data != []:
re_data[0] = re_data[0].replace("null", '1')
print(json.loads(re_data[0]))
data_dic = json.loads(re_data[0])
print(type(data_dic))
if isinstance(data_dic, dict):
re_data = data_dic
if headers["Content-Type"] != None:
params_type["Content-Type"] = headers["Content-Type"]
if params_type["Content-Type"] == "application/json":
params_type["type"] = "json"
elif params_type["Content-Type"].find("text/html") != -1 or params_type["Content-Type"].find(
"form") != -1:
params_type["type"] = "form"
else:
re_data = None
headers = json.dumps(headers)
re_data = json.dumps(re_data)
case_name = "test_" + url.split("/")[-2] + "_" + url.split("/")[-1]
make_code = f"""
#如果需要读excel测试用例传入info参数需要admin账号鉴权cookie传入admin_cookie
def {case_name}(info, admin_cookie):
allure.dynamic.feature(info["feature"]) # allure报告中一级分类
allure.dynamic.story(info["story"]) # allure报告中二级分类
allure.dynamic.title(info["title"]) # allure报告中用例名字
url = "{url}" # 接口路由
headers = {headers} # 接口请求头
json = {re_data} # 接口请求数据
expect_code = info["expected"]["code"] # 预期结果
# 构建接口请求
res = Request_handler("{method}", r"{url}", {re_data}, {headers}).post({params_type["type"]})
# --------------------分界线,下边的根据响应结果断言-----------------------------------------
res_code = jsonpath(resp, "$..code")[0] # 响应业务码
assert_equal(res_code, expect_code)
"""
with open("make_demo.txt", "w", encoding="utf8") as f:
f.write(make_code)
print("""成功生成测试脚本""")
print(make_code)
if __name__ == '__main__':
fiddler_info = """
POST https://testabb.admin.chargedot.com/api/v1//order/order/search HTTP/1.1
Host: testabb.admin.chargedot.com
Connection: keep-alive
Content-Length: 142
sec-ch-ua: " Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"
Accept: application/json, text/plain, */*
X-CSRF-TOKEN: cSSFg1JULveUmvC91vmUU14HLiN0Pi8z1PrApprn
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.106 Safari/537.36
Content-Type: application/json
Origin: https://testabb.admin.chargedot.com
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://testabb.admin.chargedot.com/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: juno_pc_session=TgfjYtMcAmTrT1hPgyqJ5BeWWW5Z807kp7zGotm1
{"status":0,"query":"","offset":0,"limit":15,"downexcel":0,"deviceId":null,"nologin":9999,"_token":"cSSFg1JULveUmvC91vmUU14HLiN0Pi8z1PrApprn"}
"""
fiddler_requests()

View File

@ -1,16 +0,0 @@
#如果需要读excel测试用例传入info参数需要admin账号鉴权cookie传入admin_cookie
def test_order_search(info, admin_cookie):
allure.dynamic.feature(info["feature"]) # allure报告中一级分类
allure.dynamic.story(info["story"]) # allure报告中二级分类
allure.dynamic.title(info["title"]) # allure报告中用例名字
url = "/api/v1//order/order/search" # 接口路由
headers = {"Host": "testabb.admin.chargedot.com", "Connection": "keep-alive", "Content-Length": "142", "User-Agent": "Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/91.0.4472.106Safari/537.36", "Content-Type": "application/json", "Origin": "https", "Referer": "https", "Accept-Encoding": "gzip,deflate,br", "Accept-Language": "zh-CN,zh;q=0.9", "Cookie": "juno_pc_session=TgfjYtMcAmTrT1hPgyqJ5BeWWW5Z807kp7zGot"} # 接口请求头
json = {"status": 0, "query": "", "offset": 0, "limit": 15, "downexcel": 0, "deviceId": 1, "nologin": 9999, "_token": "cSSFg1JULveUmvC91vmUU14HLiN0Pi8z1PrApprn"} # 接口请求数据
expect_code = info["expected"]["code"] # 预期结果
# 构建接口请求
res = Request_handler("POST", r"/api/v1//order/order/search", {"status": 0, "query": "", "offset": 0, "limit": 15, "downexcel": 0, "deviceId": 1, "nologin": 9999, "_token": "cSSFg1JULveUmvC91vmUU14HLiN0Pi8z1PrApprn"}, {"Host": "testabb.admin.chargedot.com", "Connection": "keep-alive", "Content-Length": "142", "User-Agent": "Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/91.0.4472.106Safari/537.36", "Content-Type": "application/json", "Origin": "https", "Referer": "https", "Accept-Encoding": "gzip,deflate,br", "Accept-Language": "zh-CN,zh;q=0.9", "Cookie": "juno_pc_session=TgfjYtMcAmTrT1hPgyqJ5BeWWW5Z807kp7zGot"}).post(json)
# --------------------分界线,下边的根据响应结果断言-----------------------------------------
res_code = jsonpath(resp, "$..code")[0] # 响应业务码
assert_equal(res_code, expect_code)

View File

@ -1,7 +0,0 @@
"""
======================================
Author: Flora.Chen
Time: 2021/5/27 22:41
~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~
======================================
"""

View File

@ -1,41 +0,0 @@
"""
======================================
Author: Flora.Chen
Time: 2021/5/27 22:41
~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~
======================================
"""
def ddt(cls):
"""
用来装饰测试类
:param cls:
:return:
"""
for name, value in list(cls.__dict__.items()):
if hasattr(value, "DATA"):
data = getattr(value, "DATA")
for i in data:
setattr(cls, f"test_01_{i}", value)
print(name, value)
return cls
def data(data):
"""
用来装饰测试方法
:param data: 测试数据
:return:
"""
def wrapper(func):
"""
接收测试方法
:param func:
:return:
"""
setattr(func, "DATA", data)
return func
return wrapper

View File

@ -1,558 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试报告</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.0/dist/css/bootstrap.min.css"
integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<!-- 页面样式-->
<style type="text/css">
/*标题样式*/
.title {
width: auto;
height: 60px;
text-align: center;
font: bolder 38px/60px "Microsoft YaHei UI";
}
/*汇总信息样式*/
.summary {
width: 90%;
position: absolute;
top: 120px;
margin-left: 5%;
}
.text-left {
font: bolder 20px/30px "Microsoft YaHei UI";
}
.left {
width: 50%;
float: left;
}
.right {
width: 50%;
float: right;
}
.desc {
float: left;
width: 100%;
}
.list-group-item span {
font: normal 16px/38px "Microsoft YaHei UI";
padding: 30px;
}
.list-group-item {
position: relative;
display: block;
padding: .4rem 1.25rem;
background-color: #fff;
border: 1px solid rgba(0, 0, 0, .125);
}
/* 执行信息样式 */
.test_info {
width: 90%;
position: absolute;
top: 900px;
margin-left: 5%;
color: #28a745 !important;
}
.table td, th {
border: solid 2px rgba(9, 122, 51, 0.11) !important;
padding: 0;
line-height: 40px;
text-align: center;
}
select {
border: 0;
padding: 0;
margin: 0;
height: 2em;
width: 8em;
margin-left: 2em;
}
option {
text-align: center;
height: 36px;
font: none 18px/36px "Microsoft YaHei UI";
color: #28a745 !important;
}
.test_log {
background: rgba(163, 171, 189, 0.15);
width: 100%;
height: 50px;
border-top: none;
border-bottom: none;
display: none;
text-align: left;
}
.test_log td {
text-align: left;
height: 30px;
margin: 0;
padding-left: 3em;
padding-right:3em;
font: none 18px/24px "Microsoft YaHei UI";
color: #9e141a;
}
pre {
margin: 0;
white-space: pre-wrap;
white-space: -moz-pre-wrap;
white-space: -o-pre-wrap;
word-wrap: break-word;
}
/* 测试图表显示*/
.char {
width: 90%;
position: absolute;
top: 450px;
margin-left: 5%;
color: #28a745 !important;
}
</style>
</head>
<body>
<!--报告标题-->
<div class="title text-success">
<div class="shadow-lg p-3 mb-5 bg-white rounded">测试报告</div>
</div>
<!--汇总信息-->
<div class="summary">
<p class="text-left text-success">测试结果汇总</p>
<div class="left">
<ul class="list-group">
<li class="list-group-item">
<button type="button" class="btn btn-success">测试人员</button>
<span class="text-dark">测试员</span>
</li>
<li class="list-group-item">
<button type="button" class="btn btn-success">开始时间</button>
<span class="text-dark">2021-05-27 23:03:45</span>
</li>
<li class="list-group-item">
<button type="button" class="btn btn-success">执行时间</button>
<span class="text-dark">0.00 S</span>
</li>
<li class="list-group-item">
<button type="button" class="btn btn-success">用例总数</button>
<span class="text-dark">5</span>
</li>
</ul>
</div>
<div class="right">
<ul class="list-group">
<li class="list-group-item">
<button type="button" class="btn btn-success">成功用例</button>
<span class="text-success">5</span>
</li>
<li class="list-group-item">
<button type="button" class="btn btn-danger">失败用例</button>
<span class="text-warning">0</span>
</li>
<li class="list-group-item">
<button type="button" class="btn btn-warning">错误用例</button>
<span class="text-danger">0</span>
</li>
<li class="list-group-item">
<button type="button" class="btn btn-secondary">跳过用例</button>
<span class="text-secondary">0</span>
</li>
</ul>
</div>
<div class="desc">
<ul class="list-group">
<li class="list-group-item">
<button type="button" class="btn btn-success">描述信息</button>
<span class="text-secondary">XX项目测试生成的报告</span>
</li>
</ul>
</div>
</div>
<!--测试图表-->
<div class="char">
<p class="text-left text-success">图表展示</p>
<div id="char2" style="width: 49%;height: 400px;float: left"></div>
<div id="char" style="width: 49%;height: 400px ;float: left"></div>
</div>
<!--详细信息-->
<div class="test_info">
<p class="text-left text-success">详细信息</p>
<div class="table_data">
<table class="table">
<thead class="bg-success text-light">
<tr>
<th scope="col" style="width: 5%;padding: 0">编号</th>
<th scope="col" style="width: 20%;padding: 0">
<span>测试类</span>
<select id="testClass">
<option>所有</option>
<option>TestLogin</option>
</select>
</th>
<th scope="col" style="width: 15%;padding: 0">测试方法</th>
<th scope="col" style="width: 20%;padding: 0">用例描述</th>
<th scope="col" style="width: 10%;padding: 0">执行时间</th>
<th scope="col" style="width: 20%;padding: 0">
<span>执行结果</span>
<select id="testResult">
<option>所有</option>
<option class="text-success">成功</option>
<option class="text-danger">失败</option>
<option class="text-warning">错误</option>
<option class="text-info">跳过</option>
</select>
</th>
<th scope="col" style="width: 10%;padding: 0">详细信息</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td class="TestLogin">TestLogin</td>
<td>test_01_1</td>
<td>None</td>
<td>0.0s</td>
<td class="text-success">成功</td>
<td>
<button type="button" class="btn btn-success btn_info">查看详情</button>
</td>
</tr>
<tr class="test_log">
<td colspan="7" class="small text-muted" style=" word-wrap:break-word; word-break:break-all">
<pre>测试方法
test_01_1 (myddtR.test_case.TestLogin)执行——>【通过】
</pre>
</td>
</tr>
<tr>
<td>2</td>
<td class="TestLogin">TestLogin</td>
<td>test_01_2</td>
<td>None</td>
<td>0.0s</td>
<td class="text-success">成功</td>
<td>
<button type="button" class="btn btn-success btn_info">查看详情</button>
</td>
</tr>
<tr class="test_log">
<td colspan="7" class="small text-muted" style=" word-wrap:break-word; word-break:break-all">
<pre>测试方法
test_01_2 (myddtR.test_case.TestLogin)执行——>【通过】
</pre>
</td>
</tr>
<tr>
<td>3</td>
<td class="TestLogin">TestLogin</td>
<td>test_01_3</td>
<td>None</td>
<td>0.0s</td>
<td class="text-success">成功</td>
<td>
<button type="button" class="btn btn-success btn_info">查看详情</button>
</td>
</tr>
<tr class="test_log">
<td colspan="7" class="small text-muted" style=" word-wrap:break-word; word-break:break-all">
<pre>测试方法
test_01_3 (myddtR.test_case.TestLogin)执行——>【通过】
</pre>
</td>
</tr>
<tr>
<td>4</td>
<td class="TestLogin">TestLogin</td>
<td>test_01_4</td>
<td>None</td>
<td>0.0s</td>
<td class="text-success">成功</td>
<td>
<button type="button" class="btn btn-success btn_info">查看详情</button>
</td>
</tr>
<tr class="test_log">
<td colspan="7" class="small text-muted" style=" word-wrap:break-word; word-break:break-all">
<pre>测试方法
test_01_4 (myddtR.test_case.TestLogin)执行——>【通过】
</pre>
</td>
</tr>
<tr>
<td>5</td>
<td class="TestLogin">TestLogin</td>
<td>test_login</td>
<td>None</td>
<td>0.0s</td>
<td class="text-success">成功</td>
<td>
<button type="button" class="btn btn-success btn_info">查看详情</button>
</td>
</tr>
<tr class="test_log">
<td colspan="7" class="small text-muted" style=" word-wrap:break-word; word-break:break-all">
<pre>测试方法
test_login (myddtR.test_case.TestLogin)执行——>【通过】
</pre>
</td>
</tr>
</tbody>
</table>
</div>
<div style="height: 200px"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"
integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
<script>
var tbodyTr = $('tbody tr');
var testResult = $("#testResult");
var testClass = $("#testClass");
<!-- 用例执行详细信息显示切换-->
$(".btn_info").click(function () {
$(this).parent().parent().next().toggle();
});
// 当选择用例类之后触发
testClass.change(function () {
var cls = $(this).val();
var res = testResult.val();
elementDisplay(cls, res);
sort()
});
testResult.change(function () {
var res = $(this).val();
var cls = testClass.val();
elementDisplay(cls, res);
sort()
});
function elementDisplay(cls, res) {
// 用例数据的显示
if (cls === "所有") {
if (res === "所有") {
tbodyTr.has('button').show();
} else if (res === '成功') {
tbodyTr.hide();
tbodyTr.has('button').has('.text-success').show()
} else if (res === '失败') {
tbodyTr.hide();
tbodyTr.has('button').has('.text-danger').show()
} else if (res === '错误') {
tbodyTr.hide();
tbodyTr.has('button').has('.text-warning').show()
} else if (res === '跳过') {
tbodyTr.hide();
tbodyTr.has('button').has('.text-info').show()
}
} else {
if (res === "所有") {
tbodyTr.hide();
tbodyTr.has('button').has('.' + cls + '').show()
} else if (res === '成功') {
tbodyTr.hide();
tbodyTr.has('button').has('.' + cls + '').has('.text-success').show()
} else if (res === '失败') {
tbodyTr.hide();
tbodyTr.has('button').has('.' + cls + '').has('.text-danger').show()
} else if (res === '错误') {
tbodyTr.hide();
tbodyTr.has('button').has('.' + cls + '').has('.text-warning').show()
} else if (res === '跳过') {
tbodyTr.hide();
tbodyTr.has('button').has('.' + cls + '').has('.text-info').show()
}
}
}
function sort() {
//重新排列显示序号
// 选择所有可以见的tr
var visibleTr = tbodyTr.filter(":visible");
visibleTr.each(function (index, element) {
element.firstElementChild.innerHTML = index + 1;
})
}
</script>
<script type="text/javascript">
// 基于准备好的dom初始化echarts实例
var myChart = echarts.init(document.getElementById('char'));
var myChart2 = echarts.init(document.getElementById('char2'));
// 指定图表的配置项和数据
option = {
color: ['#00a10a', '#ddb518', 'rgba(204,46,41,0.73)', '#85898c'],
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} ({d}%)'
},
legend: {
orient: 'vertical',
left: 10,
data: ['通过', '失败', '错误', '跳过']
},
series: [
{
name: '测试结果',
type: 'pie',
radius: ['50%', '70%'],
avoidLabelOverlap: false,
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: true,
fontSize: '30',
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: [
{value: 5, name: '通过'},
{value: 0, name: '失败'},
{value: 0, name: '错误'},
{value: 0, name: '跳过'}
]
}
]
};
option2 = {
tooltip: {
formatter: '{a} <br/>{b} : {c}%'
},
toolbox: {
feature: {
restore: {},
saveAsImage: {}
}
},
series: [
{
name: '测试结果',
type: 'gauge',
detail: {formatter: '100.00%'},
data: [{value: '100.00', name: '用例通过率'}],
axisLine: {
lineStyle: {
color: [
[0.2, '#c20000'],
[0.8, '#ddb518'],
[1, '#00a10a']]
}
}
}
]
};
myChart2.setOption(option2);
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
</script>
</body>
</html>

View File

@ -1,15 +0,0 @@
"""
======================================
Author: Flora.Chen
Time: 2021/5/27 22:41
~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~
======================================
"""
import unittest
import unittestreport
from myddtR.test_case import TestLogin
suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestLogin)
runner = unittestreport.TestRunner(suite)
runner.run()

View File

@ -1,16 +0,0 @@
"""
======================================
Author: Flora.Chen
Time: 2021/5/27 22:42
~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~
======================================
"""
import unittest
from myddtR.myddt import ddt, data
@ddt
class TestLogin(unittest.TestCase):
@data([1, 2, 3, 4])
def test_login(self):
print("测试方法")

View File

@ -1,116 +0,0 @@
import json
import os
import requests
from jsonpath import jsonpath
import allure
from common.yaml_handler import read_yaml
from config import path
from middleware.config_handler import Config_handler
configdata_path = os.path.join(path.config_path, "config_data.yaml")
config_info = read_yaml(configdata_path)
host_config = config_info["host"]
api_code = config_info["api_code"]
class Request_handler:
"""
二次封装requests
:param
:return
"""
def __init__(self, method, path, data, headers):
self.url = host_config + path
self.headers = headers
self.data = data
self.method = method
def post(self, params_type, **kwargs):
"""
结合allure,日志信息项目配置化信息重构post请求提升易用性
:param params_type:
:param kwargs:
:return:
"""
try:
if self.method in ["post", "POST"]:
with allure.step(f"第一步:获取请求数据。\nheaders:{self.headers}\ndata:{self.data}\nurl:{self.url}"):
Config_handler.logger.info(f"第一步:获取请求数据。\nheaders:{self.headers}\ndata:{self.data}\nurl:{self.url}")
with allure.step(f"第二步:构建{self.method }请求"):
Config_handler.logger.info(f"第二步:构建{self.method }请求")
global response
if params_type == "json":
response = requests.request(method='POST', url=self.url, headers=self.headers, json=self.data, **kwargs)
elif params_type == "form": # 发送表单数据使用data参数传递
response = requests.request(method='POST', url=self.url, headers=self.headers, data=self.data, **kwargs)
else:
Config_handler.logger.error(f"{self.method}请求数据类型参数为json或者form实际参数为{params_type}")
res_data = response.json()
Config_handler.logger.info(f"响应数据为{res_data}")
response_code = jsonpath(res_data, "$..code")[0]
Config_handler.logger.info('请求参数:{}'.format(self.data))
if response_code == 0:
with allure.step(f"第三步:判断请求结果,{self.method}请求成功"):
Config_handler.logger.info(f"第三步:判断请求结果,{self.method}请求成功")
if res_data is not None:
with allure.step(f"第四步:获取响应数据\n{res_data}"):
Config_handler.logger.info(f"第四步:获取响应数据\n{res_data}")
elif response_code in api_code.keys():
"""获取业务code进行失败原因分析"""
with allure.step(f"第三步:判断请求结果,{self.method}请求成功"):
print(response_code)
code = api_code[response_code]
with allure.step(f"第四步:响应结果为code:{response_code} \t失败原因:{code}"):
Config_handler.logger.info(f"判断请求结果,{self.method}请求失败。code:{response_code} \t失败原因:{code}")
else:
Config_handler.logger.info(f"第三步:判断请求结果,{self.method}请求失败。code:{response_code}业务状态码未维护 \t失败原因:未知")
return response.json()
else:
Config_handler.logger.err(f"请求方法不为post实际输入请求方法为{self.method}")
raise ValueError('request method "{}" error ! please check'.format(self.method))
except requests.RequestException as e:
Config_handler.logger.err(f"请求错误:\n{e}")
raise
def get(self):
try:
if self.method in ["get", "GET"]:
with allure.step(f"第一步:获取请求数据。\nheaders:{self.headers}\ndata:{self.data}\nurl:{self.url}"):
Config_handler.logger.info(f"第一步:获取请求数据。\nheaders:{self.headers}\ndata:{self.data}\nurl:{self.url}")
with allure.step(f"第二步:构建{self.method }请求"):
Config_handler.logger.info(f"第二步:构建{self.method }请求")
response = requests.request(
method='get', url=self.url, headers=self.headers, params=self.data)
res_data = response.json()
response_code = jsonpath(res_data, "$..code")[0]
if len(data) != 0:
Config_handler.logger.info('请求参数:{}'.format(json.dumps(self.data)))
if response_code == 0:
with allure.step(f"第三步:判断请求结果,{self.method}请求成功"):
Config_handler.logger.info(f"第三步:判断请求结果,{self.method}请求成功")
if res_data is not None:
with allure.step(f"第四步:获取响应数据\n{res_data}"):
Config_handler.logger.info(f"第四步:获取响应数据\n{res_data}")
elif response_code in api_code.keys():
Config_handler.logger.info("调试",response_code, api_code.keys())
# code = api_code[response_code]
# Config_handler.logger.info(f"第三步:判断请求结果,{self.method}请求失败。code:{response_code} \t失败原因:{code}")
else:
Config_handler.logger.info(f"第三步:判断请求结果,{self.method}请求失败。code:{response_code}未维护 \t失败原因:未知")
return response.json()
else:
Config_handler.logger.err(f"请求方法不为post实际输入请求方法为{self.method}")
except requests.RequestException as e:
Config_handler.logger.err(f"请求错误\n{e}")
if __name__ == '__main__':
headers = {"Content-Type": "application/json"}
data ={'name': 'admin@chargedot.com', 'pwd': '26a50c46349c1d990376022bd62f7251'}
a = Request_handler("post", "/api/v1//system/user/login", data, headers).post("json")
# b = jsonpath(a, "$..token")[0]
# print(b)

View File

@ -1,109 +0,0 @@
"""
============================
author:MuSen
time:2019/6/21
E-mail:3247119728@qq.com
============================
"""
from flask import Flask, request, jsonify
from flask_cors import CORS
app = Flask(__name__)
# 测试数据
user_info = {"user": 'python01', 'pwd': 'lemonban'}
project_data = {"code": "1",
"data": [{"title": "前程贷", "id": "1001"},
{"title": "智慧金融", "id": "1002"},
{"title": "生鲜到家", "id": "1003"},
{"title": "柠檬班app", "id": "1004"}],
"msg": "四个项目",
}
# 接口数据
interface_data = {
"1001": {"code": "1",
"data": [{"name": "前程贷登录1001"},
{"name": "前程贷注册1001"}],
"msg": "2个接口", },
"1002": {"code": "1",
"data": [{"name": "智慧-登录1002"},
{"name": "智慧-注册1002"},
{"name": "智慧-贷款1004"}, ],
"msg": "3个接口", },
"1003": {"code": "1",
"data": [{"name": "生鲜-登录1003"},
{"name": "生鲜-注册1003"},
{"name": "生鲜下单1003"}, ],
"msg": "3个接口", },
"1004": {"code": "1",
"data": [{"name": "app登录1004"},
{"name": "app注册1004"},
{"name": "app报名1004"},
{"name": "app缴费1004"},
],
"msg": "4个接口", },
}
# 登录
@app.route('/api/user/login', methods=['post'])
def login():
"""
接口地址http://127.0.0.1:5000/api/user/login
请求方法post
参数 {user:账号,pwd:密码}
参数类型表单 json都支持
返回:登录之后的结果
"""
data = request.form or request.json
# 判断账号,密码是否正确
if user_info.get('user') == data.get('user') and user_info.get('pwd') == data.get('pwd'):
return jsonify({'code': "1", "data": None, "msg": "成功"})
else:
return jsonify({'code': "0", "data": None, "msg": "账号或密码有误"})
# 获取项目列表
@app.route('/api/projects', methods=['get'])
def pro_list():
"""
接口地址http://127.0.0.1:5000/api/projects
请求方法get
参数
返回所有的项目
:return:
"""
return jsonify(project_data)
# 获取接口列表
@app.route('/api/interface', methods=['get'])
def interface():
"""
接口地址http://127.0.0.1:5000/api/interface
请求方法get
参数 id(项目的id)
参数类型查询字符串
返回:该项目的所有接口
"""
inter_id = request.args.get('id')
if inter_id:
res_data = interface_data.get(inter_id)
if res_data:
return jsonify(res_data)
else:
return jsonify({"code": "0", "data": None, "msg": "没有该项目"})
else:
return jsonify({"code": "0", "data": None, "msg": "参数id不能为空"})
if __name__ == '__main__':
cors = CORS(app)
app.run(debug=True)

View File

@ -1,137 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<!--引入axios -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<!-- <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> -->
<!--引入VUE -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!--引入elementUI-->
<link rel="stylesheet" href="https://unpkg.com/element-plus/lib/theme-chalk/index.css">
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<!--引入vue-router-->
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<style type="text/css">
.login{
width: 600px;
height: 400px;
margin: 100px auto;
}
</style>
</head>
<body>
<div id="app">
<el-container>
<el-header>Header</el-header>
<el-card>
<el-main>
<div class="login">
<h2 style="text-align:center;">登录</h2>
<el-form :model="form" label-width="80px" method="post">
<el-form-item label="账号">
<el-input v-model="form.username" placeholder="请输入用户名"></el-input>
</el-form-item>
<el-form-item label="密码">
<el-input v-model="form.password" placeholder="请输入密码" show-password></el-input>
</el-form-item>
<el-form-item style="text-align:right;">
<el-button type="primary" @click="login" round>登录</el-button>
</el-form-item>
</el-form>
</div>
<hr/>
<div>
<el-button type="info" @click="getProject" round>项目列表</el-button>
<el-table :data="projects" stripe style="width: 100%">
<el-table-column prop="id" label="ID"width="180"></el-table-column>
<el-table-column prop="name" label="项目名" width="180"></el-table-column>
<el-table-column prop="create_time" label="创建时间" width="180"></el-table-column>
<el-table-column prop="leader" label="负责人"width="180"></el-table-column>
<el-table-column prop="tester" label="测试者"width="180"></el-table-column>
<el-table-column prop="testcases" label="用例数"width="180"></el-table-column>
</el-table>
</div>
</el-main>
</el-card>
<el-footer>Footer</el-footer>
</el-container>
</div>
<script type="text/javascript">
// 创建请求对象
const http = axios.create({
// 设置基本的url地址
baseURL: 'http://api.keyou.site:8000',
timeout: 1000,
// 指定http状态码错误范围
validateStatus: function(status) {
return true
}
})
// 请求拦截器
http.interceptors.request.use(function(config){
// 获取sessionStore中的token值添加到请求信息中
token = window.sessionStorage.getItem("token")
if (token){
config.headers.Authorization = "JWT " + token
}
return config;
})
const Login = {template: `<h1>登录页面</h1>`}
const Home = {template: `<h1>项目首页</h1>`}
const router = new VueRouter({
routers: [
{path: "/login", component: Login}
{path: "/home", component: Home}
]
})
var vm = new Vue({
el: "#app",
router,
data: {
form: {
username: "",
password: ""
},
projects: []
},
methods: {
async login(){
// 发送登录请求
const response = await http.post("/user/login/", this.form)
// const response = await http.post('/user/login', this.form)
console.log(response.data)
if (response.status === 200){
// 提取响应中的token
const token = response.data.token
// 将token存储到sessionstorage中
window.sessionStorage.setItem("token", token)
alert("登录成功")
}else{
alert("登录失败!")
}
},
// 发送请求获取所有项目
async getProject(){
const response = await http.get("/projects/")
console.log(response)
if (response.status === 200){
this.projects = response.data.results
}
}
}
})
</script>
</body>
</html>

View File

@ -1,685 +0,0 @@
# Changelog
### 0.21.1 (December 21, 2020)
Fixes and Functionality:
- Hotfix: Prevent SSRF (#3410)
- Protocol not parsed when setting proxy config from env vars (#3070)
- Updating axios in types to be lower case (#2797)
- Adding a type guard for `AxiosError` (#2949)
Internal and Tests:
- Remove the skipping of the `socket` http test (#3364)
- Use different socket for Win32 test (#3375)
Huge thanks to everyone who contributed to this release via code (authors listed below) or via reviews and triaging on GitHub:
- Daniel Lopretto <timemachine3030@users.noreply.github.com>
- Jason Kwok <JasonHK@users.noreply.github.com>
- Jay <jasonsaayman@gmail.com>
- Jonathan Foster <jonathan@jonathanfoster.io>
- Remco Haszing <remcohaszing@gmail.com>
- Xianming Zhong <chinesedfan@qq.com>
### 0.21.0 (October 23, 2020)
Fixes and Functionality:
- Fixing requestHeaders.Authorization ([#3287](https://github.com/axios/axios/pull/3287))
- Fixing node types ([#3237](https://github.com/axios/axios/pull/3237))
- Fixing axios.delete ignores config.data ([#3282](https://github.com/axios/axios/pull/3282))
- Revert "Fixing overwrite Blob/File type as Content-Type in browser. (#1773)" ([#3289](https://github.com/axios/axios/pull/3289))
- Fixing an issue that type 'null' and 'undefined' is not assignable to validateStatus when typescript strict option is enabled ([#3200](https://github.com/axios/axios/pull/3200))
Internal and Tests:
- Lock travis to not use node v15 ([#3361](https://github.com/axios/axios/pull/3361))
Documentation:
- Fixing simple typo, existant -> existent ([#3252](https://github.com/axios/axios/pull/3252))
- Fixing typos ([#3309](https://github.com/axios/axios/pull/3309))
Huge thanks to everyone who contributed to this release via code (authors listed below) or via reviews and triaging on GitHub:
- Allan Cruz <57270969+Allanbcruz@users.noreply.github.com>
- George Cheng <Gerhut@GMail.com>
- Jay <jasonsaayman@gmail.com>
- Kevin Kirsche <Kev.Kirsche+GitHub@gmail.com>
- Remco Haszing <remcohaszing@gmail.com>
- Taemin Shin <cprayer13@gmail.com>
- Tim Gates <tim.gates@iress.com>
- Xianming Zhong <chinesedfan@qq.com>
### 0.20.0 (August 20, 2020)
Release of 0.20.0-pre as a full release with no other changes.
### 0.20.0-pre (July 15, 2020)
Fixes and Functionality:
- Fixing response with utf-8 BOM can not parse to json ([#2419](https://github.com/axios/axios/pull/2419))
- fix: remove byte order marker (UTF-8 BOM) when transform response
- fix: remove BOM only utf-8
- test: utf-8 BOM
- fix: incorrect param name
- Refactor mergeConfig without utils.deepMerge ([#2844](https://github.com/axios/axios/pull/2844))
- Adding failing test
- Fixing #2587 default custom config persisting
- Adding Concat keys and filter duplicates
- Fixed value from CPE
- update for review feedbacks
- no deepMerge
- only merge between plain objects
- fix rename
- always merge config by mergeConfig
- extract function mergeDeepProperties
- refactor mergeConfig with all keys, and add special logic for validateStatus
- add test for resetting headers
- add lots of tests and fix a bug
- should not inherit `data`
- use simple toString
- Fixing overwrite Blob/File type as Content-Type in browser. ([#1773](https://github.com/axios/axios/pull/1773))
- Fixing an issue that type 'null' is not assignable to validateStatus ([#2773](https://github.com/axios/axios/pull/2773))
- Fixing special char encoding ([#1671](https://github.com/axios/axios/pull/1671))
- removing @ character from replacement list since it is a reserved character
- Updating buildURL test to not include the @ character
- Removing console logs
- Fixing password encoding with special characters in basic authentication ([#1492](https://github.com/axios/axios/pull/1492))
- Fixing password encoding with special characters in basic authentication
- Adding test to check if password with non-Latin1 characters pass
- Fixing 'Network Error' in react native android ([#1487](https://github.com/axios/axios/pull/1487))
There is a bug in react native Android platform when using get method. It will trigger a 'Network Error' when passing the requestData which is an empty string to request.send function. So if the requestData is an empty string we can set it to null as well to fix the bug.
- Fixing Cookie Helper with Asyc Components ([#1105](https://github.com/axios/axios/pull/1105)) ([#1107](https://github.com/axios/axios/pull/1107))
- Fixing 'progressEvent' type ([#2851](https://github.com/axios/axios/pull/2851))
- Fix 'progressEvent' type
- Update axios.ts
- Fixing getting local files (file://) failed ([#2470](https://github.com/axios/axios/pull/2470))
- fix issue #2416, #2396
- fix Eslint warn
- Modify judgment conditions
- add unit test
- update unit test
- update unit test
- Allow PURGE method in typings ([#2191](https://github.com/axios/axios/pull/2191))
- Adding option to disable automatic decompression ([#2661](https://github.com/axios/axios/pull/2661))
- Adding ability to disable auto decompression
- Updating decompress documentation in README
- Fixing test\unit\adapters\http.js lint errors
- Adding test for disabling auto decompression
- Removing changes that fixed lint errors in tests
- Removing formatting change to unit test
- Add independent `maxBodyLength` option ([#2781](https://github.com/axios/axios/pull/2781))
- Add independent option to set the maximum size of the request body
- Remove maxBodyLength check
- Update README
- Assert for error code and message
- Adding responseEncoding to mergeConfig ([#1745](https://github.com/axios/axios/pull/1745))
- Compatible with follow-redirect aborts the request ([#2689](https://github.com/axios/axios/pull/2689))
- Compatible with follow-redirect aborts the request
- Use the error code
- Fix merging of params ([#2656](https://github.com/axios/axios/pull/2656))
- Name function to avoid ESLint func-names warning
- Switch params config to merge list and update tests
- Restore testing of both false and null
- Restore test cases for keys without defaults
- Include test for non-object values that aren't false-y.
- Revert `finally` as `then` ([#2683](https://github.com/axios/axios/pull/2683))
Internal and Tests:
- Fix stale bot config ([#3049](https://github.com/axios/axios/pull/3049))
- fix stale bot config
- fix multiple lines
- Add days and change name to work ([#3035](https://github.com/axios/axios/pull/3035))
- Update close-issues.yml ([#3031](https://github.com/axios/axios/pull/3031))
- Update close-issues.yml
Update close message to read better 😄
- Fix use of quotations
Use single quotes as per other .yml files
- Remove user name form message
- Add GitHub actions to close stale issues/prs ([#3029](https://github.com/axios/axios/pull/3029))
- prepare stale actions
- update messages
- Add exempt labels and lighten up comments
- Add GitHub actions to close invalid issues ([#3022](https://github.com/axios/axios/pull/3022))
- add close actions
- fix with checkout
- update issue templates
- add reminder
- update close message
- Add test with Node.js 12 ([#2860](https://github.com/axios/axios/pull/2860))
- test with Node.js 12
- test with latest
- Adding console log on sandbox server startup ([#2210](https://github.com/axios/axios/pull/2210))
- Adding console log on sandbox server startup
- Update server.js
Add server error handling
- Update server.js
Better error message, remove retry.
- Adding tests for method `options` type definitions ([#1996](https://github.com/axios/axios/pull/1996))
Update tests.
- Add test for redirecting with too large response ([#2695](https://github.com/axios/axios/pull/2695))
- Fixing unit test failure in Windows OS ([#2601](https://github.com/axios/axios/pull/2601))
- Fixing issue for HEAD method and gzipped response ([#2666](https://github.com/axios/axios/pull/2666))
- Fix tests in browsers ([#2748](https://github.com/axios/axios/pull/2748))
- chore: add `jsdelivr` and `unpkg` support ([#2443](https://github.com/axios/axios/pull/2443))
Documentation:
- Adding support for URLSearchParams in node ([#1900](https://github.com/axios/axios/pull/1900))
- Adding support for URLSearchParams in node
- Remove un-needed code
- Update utils.js
- Make changes as suggested
- Adding table of content (preview) ([#3050](https://github.com/axios/axios/pull/3050))
- add toc (preview)
- remove toc in toc
Signed-off-by: Moni <usmoni@gmail.com>
- fix sublinks
- fix indentation
- remove redundant table links
- update caps and indent
- remove axios
- Replace 'blacklist' with 'blocklist' ([#3006](https://github.com/axios/axios/pull/3006))
- docs(): Detailed config options environment. ([#2088](https://github.com/axios/axios/pull/2088))
- docs(): Detailed config options environment.
- Update README.md
- Include axios-data-unpacker in ECOSYSTEM.md ([#2080](https://github.com/axios/axios/pull/2080))
- Allow opening examples in Gitpod ([#1958](https://github.com/axios/axios/pull/1958))
- Remove axios.all() and axios.spread() from Readme.md ([#2727](https://github.com/axios/axios/pull/2727))
- remove axios.all(), axios.spread()
- replace example
- axios.all() -> Promise.all()
- axios.spread(function (acct, perms)) -> function (acct, perms)
- add deprecated mark
- Update README.md ([#2887](https://github.com/axios/axios/pull/2887))
Small change to the data attribute doc of the config. A request body can also be set for DELETE methods but this wasn't mentioned in the documentation (it only mentioned POST, PUT and PATCH). Took my some 10-20 minutes until I realized that I don't need to manipulate the request body with transformRequest in the case of DELETE.
- Include swagger-taxos-codegen in ECOSYSTEM.md ([#2162](https://github.com/axios/axios/pull/2162))
- Add CDNJS version badge in README.md ([#878](https://github.com/axios/axios/pull/878))
This badge will show the version on CDNJS!
- Documentation update to clear up ambiguity in code examples ([#2928](https://github.com/axios/axios/pull/2928))
- Made an adjustment to the documentation to clear up any ambiguity around the use of "fs". This should help clear up that the code examples with "fs" cannot be used on the client side.
- Update README.md about validateStatus ([#2912](https://github.com/axios/axios/pull/2912))
Rewrote the comment from "Reject only if the status code is greater than or equal to 500" to "Resolve only if the status code is less than 500"
- Updating documentation for usage form-data ([#2805](https://github.com/axios/axios/pull/2805))
Closes #2049
- Fixing CHANGELOG.md issue link ([#2784](https://github.com/axios/axios/pull/2784))
- Include axios-hooks in ECOSYSTEM.md ([#2003](https://github.com/axios/axios/pull/2003))
- Added Response header access instructions ([#1901](https://github.com/axios/axios/pull/1901))
- Added Response header access instructions
- Added note about using bracket notation
- Add `onUploadProgress` and `onDownloadProgress` are browser only ([#2763](https://github.com/axios/axios/pull/2763))
Saw in #928 and #1966 that `onUploadProgress` and `onDownloadProgress` only work in the browser and was missing that from the README.
- Update ' sign to ` in proxy spec ([#2778](https://github.com/axios/axios/pull/2778))
- Adding jsDelivr link in README ([#1110](https://github.com/axios/axios/pull/1110))
- Adding jsDelivr link
- Add SRI
- Remove SRI
Huge thanks to everyone who contributed to this release via code (authors listed
below) or via reviews and triaging on GitHub:
- Alan Wang <wp_scut@163.com>
- Alexandru Ungureanu <khakcarot@gmail.com>
- Anubhav Srivastava <anubhav.srivastava00@gmail.com>
- Benny Neugebauer <bn@bennyn.de>
- Cr <631807682@qq.com>
- David <cygnidavid@gmail.com>
- David Ko <david.ko@pvtmethod.com>
- David Tanner <david.tanner@lifeomic.com>
- Emily Morehouse <emilyemorehouse@gmail.com>
- Felipe Martins <felipewmartins@gmail.com>
- Fonger <5862369+Fonger@users.noreply.github.com>
- Frostack <soulburn007@gmail.com>
- George Cheng <Gerhut@GMail.com>
- grumblerchester <grumblerchester@users.noreply.github.com>
- Gustavo López <gualopezb@gmail.com>
- hexaez <45806662+hexaez@users.noreply.github.com>
- huangzuizui <huangzuizui@gmail.com>
- Ian Wijma <ian@wij.ma>
- Jay <jasonsaayman@gmail.com>
- jeffjing <zgayjjf@qq.com>
- jennynju <46782518+jennynju@users.noreply.github.com>
- Jimmy Liao <52391190+jimmy-liao-gogoro@users.noreply.github.com>
- Jonathan Sharpe <j.r.sharpe@gmail.com>
- JounQin <admin@1stg.me>
- Justin Beckwith <justin.beckwith@gmail.com>
- Kamil Posiadała <3dcreator.pl@gmail.com>
- Lukas Drgon <lukas.drgon@gmail.com>
- marcinx <mail@marcinx.com>
- Martti Laine <martti@codeclown.net>
- Michał Zarach <michal.m.zarach@gmail.com>
- Moni <usmoni@gmail.com>
- Motonori Iwata <121048+iwata@users.noreply.github.com>
- Nikita Galkin <nikita@galk.in>
- Petr Mares <petr@mares.tw>
- Philippe Recto <precto1285@gmal.com>
- Remco Haszing <remcohaszing@gmail.com>
- rockcs1992 <chengshi1219@gmail.com>
- Ryan Bown <rbown@niftee.com.au>
- Samina Fu <sufuf3@gmail.com>
- Simone Busoli <simone.busoli@gmail.com>
- Spencer von der Ohe <s.vonderohe40@gmail.com>
- Sven Efftinge <sven.efftinge@typefox.io>
- Taegyeoung Oh <otk1090@naver.com>
- Taemin Shin <cprayer13@gmail.com>
- Thibault Ehrhart <1208424+ehrhart@users.noreply.github.com>
- Xianming Zhong <chinesedfan@qq.com>
- Yasu Flores <carlosyasu91@gmail.com>
- Zac Delventhal <delventhalz@gmail.com>
### 0.19.2 (Jan 20, 2020)
- Remove unnecessary XSS check ([#2679](https://github.com/axios/axios/pull/2679)) (see ([#2646](https://github.com/axios/axios/issues/2646)) for discussion)
### 0.19.1 (Jan 7, 2020)
Fixes and Functionality:
- Fixing invalid agent issue ([#1904](https://github.com/axios/axios/pull/1904))
- Fix ignore set withCredentials false ([#2582](https://github.com/axios/axios/pull/2582))
- Delete useless default to hash ([#2458](https://github.com/axios/axios/pull/2458))
- Fix HTTP/HTTPs agents passing to follow-redirect ([#1904](https://github.com/axios/axios/pull/1904))
- Fix ignore set withCredentials false ([#2582](https://github.com/axios/axios/pull/2582))
- Fix CI build failure ([#2570](https://github.com/axios/axios/pull/2570))
- Remove dependency on is-buffer from package.json ([#1816](https://github.com/axios/axios/pull/1816))
- Adding options typings ([#2341](https://github.com/axios/axios/pull/2341))
- Adding Typescript HTTP method definition for LINK and UNLINK. ([#2444](https://github.com/axios/axios/pull/2444))
- Update dist with newest changes, fixes Custom Attributes issue
- Change syntax to see if build passes ([#2488](https://github.com/axios/axios/pull/2488))
- Update Webpack + deps, remove now unnecessary polyfills ([#2410](https://github.com/axios/axios/pull/2410))
- Fix to prevent XSS, throw an error when the URL contains a JS script ([#2464](https://github.com/axios/axios/pull/2464))
- Add custom timeout error copy in config ([#2275](https://github.com/axios/axios/pull/2275))
- Add error toJSON example ([#2466](https://github.com/axios/axios/pull/2466))
- Fixing Vulnerability A Fortify Scan finds a critical Cross-Site Scrip… ([#2451](https://github.com/axios/axios/pull/2451))
- Fixing subdomain handling on no_proxy ([#2442](https://github.com/axios/axios/pull/2442))
- Make redirection from HTTP to HTTPS work ([#2426](https://github.com/axios/axios/pull/2426)) and ([#2547](https://github.com/axios/axios/pull/2547))
- Add toJSON property to AxiosError type ([#2427](https://github.com/axios/axios/pull/2427))
- Fixing socket hang up error on node side for slow response. ([#1752](https://github.com/axios/axios/pull/1752))
- Alternative syntax to send data into the body ([#2317](https://github.com/axios/axios/pull/2317))
- Fixing custom config options ([#2207](https://github.com/axios/axios/pull/2207))
- Fixing set `config.method` after mergeConfig for Axios.prototype.request ([#2383](https://github.com/axios/axios/pull/2383))
- Axios create url bug ([#2290](https://github.com/axios/axios/pull/2290))
- Do not modify config.url when using a relative baseURL (resolves [#1628](https://github.com/axios/axios/issues/1098)) ([#2391](https://github.com/axios/axios/pull/2391))
- Add typescript HTTP method definition for LINK and UNLINK ([#2444](https://github.com/axios/axios/pull/2444))
Internal:
- Revert "Update Webpack + deps, remove now unnecessary polyfills" ([#2479](https://github.com/axios/axios/pull/2479))
- Order of if/else blocks is causing unit tests mocking XHR. ([#2201](https://github.com/axios/axios/pull/2201))
- Add license badge ([#2446](https://github.com/axios/axios/pull/2446))
- Fix travis CI build [#2386](https://github.com/axios/axios/pull/2386)
- Fix cancellation error on build master. #2290 #2207 ([#2407](https://github.com/axios/axios/pull/2407))
Documentation:
- Fixing typo in CHANGELOG.md: s/Functionallity/Functionality ([#2639](https://github.com/axios/axios/pull/2639))
- Fix badge, use master branch ([#2538](https://github.com/axios/axios/pull/2538))
- Fix typo in changelog [#2193](https://github.com/axios/axios/pull/2193)
- Document fix ([#2514](https://github.com/axios/axios/pull/2514))
- Update docs with no_proxy change, issue #2484 ([#2513](https://github.com/axios/axios/pull/2513))
- Fixing missing words in docs template ([#2259](https://github.com/axios/axios/pull/2259))
- 🐛Fix request finally documentation in README ([#2189](https://github.com/axios/axios/pull/2189))
- updating spelling and adding link to docs ([#2212](https://github.com/axios/axios/pull/2212))
- docs: minor tweak ([#2404](https://github.com/axios/axios/pull/2404))
- Update response interceptor docs ([#2399](https://github.com/axios/axios/pull/2399))
- Update README.md ([#2504](https://github.com/axios/axios/pull/2504))
- Fix word 'sintaxe' to 'syntax' in README.md ([#2432](https://github.com/axios/axios/pull/2432))
- updating README: notes on CommonJS autocomplete ([#2256](https://github.com/axios/axios/pull/2256))
- Fix grammar in README.md ([#2271](https://github.com/axios/axios/pull/2271))
- Doc fixes, minor examples cleanup ([#2198](https://github.com/axios/axios/pull/2198))
### 0.19.0 (May 30, 2019)
Fixes and Functionality:
- Added support for no_proxy env variable ([#1693](https://github.com/axios/axios/pull/1693/files)) - Chance Dickson
- Unzip response body only for statuses != 204 ([#1129](https://github.com/axios/axios/pull/1129)) - drawski
- Destroy stream on exceeding maxContentLength (fixes [#1098](https://github.com/axios/axios/issues/1098)) ([#1485](https://github.com/axios/axios/pull/1485)) - Gadzhi Gadzhiev
- Makes Axios error generic to use AxiosResponse ([#1738](https://github.com/axios/axios/pull/1738)) - Suman Lama
- Fixing Mocha tests by locking follow-redirects version to 1.5.10 ([#1993](https://github.com/axios/axios/pull/1993)) - grumblerchester
- Allow uppercase methods in typings. ([#1781](https://github.com/axios/axios/pull/1781)) - Ken Powers
- Fixing building url with hash mark ([#1771](https://github.com/axios/axios/pull/1771)) - Anatoly Ryabov
- This commit fix building url with hash map (fragment identifier) when parameters are present: they must not be added after `#`, because client cut everything after `#`
- Preserve HTTP method when following redirect ([#1758](https://github.com/axios/axios/pull/1758)) - Rikki Gibson
- Add `getUri` signature to TypeScript definition. ([#1736](https://github.com/axios/axios/pull/1736)) - Alexander Trauzzi
- Adding isAxiosError flag to errors thrown by axios ([#1419](https://github.com/axios/axios/pull/1419)) - Ayush Gupta
Internal:
- Fixing .eslintrc without extension ([#1789](https://github.com/axios/axios/pull/1789)) - Manoel
- Fix failing SauceLabs tests by updating configuration - Emily Morehouse
- Add issue templates - Emily Morehouse
Documentation:
- Consistent coding style in README ([#1787](https://github.com/axios/axios/pull/1787)) - Ali Servet Donmez
- Add information about auth parameter to README ([#2166](https://github.com/axios/axios/pull/2166)) - xlaguna
- Add DELETE to list of methods that allow data as a config option ([#2169](https://github.com/axios/axios/pull/2169)) - Daniela Borges Matos de Carvalho
- Update ECOSYSTEM.md - Add Axios Endpoints ([#2176](https://github.com/axios/axios/pull/2176)) - Renan
- Add r2curl in ECOSYSTEM ([#2141](https://github.com/axios/axios/pull/2141)) - 유용우 / CX
- Update README.md - Add instructions for installing with yarn ([#2036](https://github.com/axios/axios/pull/2036)) - Victor Hermes
- Fixing spacing for README.md ([#2066](https://github.com/axios/axios/pull/2066)) - Josh McCarty
- Update README.md. - Change `.then` to `.finally` in example code ([#2090](https://github.com/axios/axios/pull/2090)) - Omar Cai
- Clarify what values responseType can have in Node ([#2121](https://github.com/axios/axios/pull/2121)) - Tyler Breisacher
- docs(ECOSYSTEM): add axios-api-versioning ([#2020](https://github.com/axios/axios/pull/2020)) - Weffe
- It seems that `responseType: 'blob'` doesn't actually work in Node (when I tried using it, response.data was a string, not a Blob, since Node doesn't have Blobs), so this clarifies that this option should only be used in the browser
- Update README.md. - Add Querystring library note ([#1896](https://github.com/axios/axios/pull/1896)) - Dmitriy Eroshenko
- Add react-hooks-axios to Libraries section of ECOSYSTEM.md ([#1925](https://github.com/axios/axios/pull/1925)) - Cody Chan
- Clarify in README that default timeout is 0 (no timeout) ([#1750](https://github.com/axios/axios/pull/1750)) - Ben Standefer
### 0.19.0-beta.1 (Aug 9, 2018)
**NOTE:** This is a beta version of this release. There may be functionality that is broken in
certain browsers, though we suspect that builds are hanging and not erroring. See
https://saucelabs.com/u/axios for the most up-to-date information.
New Functionality:
- Add getUri method ([#1712](https://github.com/axios/axios/issues/1712))
- Add support for no_proxy env variable ([#1693](https://github.com/axios/axios/issues/1693))
- Add toJSON to decorated Axios errors to facilitate serialization ([#1625](https://github.com/axios/axios/issues/1625))
- Add second then on axios call ([#1623](https://github.com/axios/axios/issues/1623))
- Typings: allow custom return types
- Add option to specify character set in responses (with http adapter)
Fixes:
- Fix Keep defaults local to instance ([#385](https://github.com/axios/axios/issues/385))
- Correctly catch exception in http test ([#1475](https://github.com/axios/axios/issues/1475))
- Fix accept header normalization ([#1698](https://github.com/axios/axios/issues/1698))
- Fix http adapter to allow HTTPS connections via HTTP ([#959](https://github.com/axios/axios/issues/959))
- Fix Removes usage of deprecated Buffer constructor. ([#1555](https://github.com/axios/axios/issues/1555), [#1622](https://github.com/axios/axios/issues/1622))
- Fix defaults to use httpAdapter if available ([#1285](https://github.com/axios/axios/issues/1285))
- Fixing defaults to use httpAdapter if available
- Use a safer, cross-platform method to detect the Node environment
- Fix Reject promise if request is cancelled by the browser ([#537](https://github.com/axios/axios/issues/537))
- [Typescript] Fix missing type parameters on delete/head methods
- [NS]: Send `false` flag isStandardBrowserEnv for Nativescript
- Fix missing type parameters on delete/head
- Fix Default method for an instance always overwritten by get
- Fix type error when socketPath option in AxiosRequestConfig
- Capture errors on request data streams
- Decorate resolve and reject to clear timeout in all cases
Huge thanks to everyone who contributed to this release via code (authors listed
below) or via reviews and triaging on GitHub:
- Andrew Scott <ascott18@gmail.com>
- Anthony Gauthier <antho325@hotmail.com>
- arpit <arpit2438735@gmail.com>
- ascott18
- Benedikt Rötsch <axe312ger@users.noreply.github.com>
- Chance Dickson <me@chancedickson.com>
- Dave Stewart <info@davestewart.co.uk>
- Deric Cain <deric.cain@gmail.com>
- Guillaume Briday <guillaumebriday@gmail.com>
- Jacob Wejendorp <jacob@wejendorp.dk>
- Jim Lynch <mrdotjim@gmail.com>
- johntron
- Justin Beckwith <beckwith@google.com>
- Justin Beckwith <justin.beckwith@gmail.com>
- Khaled Garbaya <khaledgarbaya@gmail.com>
- Lim Jing Rong <jjingrong@users.noreply.github.com>
- Mark van den Broek <mvdnbrk@gmail.com>
- Martti Laine <martti@codeclown.net>
- mattridley
- mattridley <matt.r@joinblink.com>
- Nicolas Del Valle <nicolas.delvalle@gmail.com>
- Nilegfx
- pbarbiero
- Rikki Gibson <rikkigibson@gmail.com>
- Sako Hartounian <sakohartounian@yahoo.com>
- Shane Fitzpatrick <fitzpasd@gmail.com>
- Stephan Schneider <stephanschndr@gmail.com>
- Steven <steven@ceriously.com>
- Tim Garthwaite <tim.garthwaite@jibo.com>
- Tim Johns <timjohns@yahoo.com>
- Yutaro Miyazaki <yutaro@studio-rubbish.com>
### 0.18.0 (Feb 19, 2018)
- Adding support for UNIX Sockets when running with Node.js ([#1070](https://github.com/axios/axios/pull/1070))
- Fixing typings ([#1177](https://github.com/axios/axios/pull/1177)):
- AxiosRequestConfig.proxy: allows type false
- AxiosProxyConfig: added auth field
- Adding function signature in AxiosInstance interface so AxiosInstance can be invoked ([#1192](https://github.com/axios/axios/pull/1192), [#1254](https://github.com/axios/axios/pull/1254))
- Allowing maxContentLength to pass through to redirected calls as maxBodyLength in follow-redirects config ([#1287](https://github.com/axios/axios/pull/1287))
- Fixing configuration when using an instance - method can now be set ([#1342](https://github.com/axios/axios/pull/1342))
### 0.17.1 (Nov 11, 2017)
- Fixing issue with web workers ([#1160](https://github.com/axios/axios/pull/1160))
- Allowing overriding transport ([#1080](https://github.com/axios/axios/pull/1080))
- Updating TypeScript typings ([#1165](https://github.com/axios/axios/pull/1165), [#1125](https://github.com/axios/axios/pull/1125), [#1131](https://github.com/axios/axios/pull/1131))
### 0.17.0 (Oct 21, 2017)
- **BREAKING** Fixing issue with `baseURL` and interceptors ([#950](https://github.com/axios/axios/pull/950))
- **BREAKING** Improving handing of duplicate headers ([#874](https://github.com/axios/axios/pull/874))
- Adding support for disabling proxies ([#691](https://github.com/axios/axios/pull/691))
- Updating TypeScript typings with generic type parameters ([#1061](https://github.com/axios/axios/pull/1061))
### 0.16.2 (Jun 3, 2017)
- Fixing issue with including `buffer` in bundle ([#887](https://github.com/axios/axios/pull/887))
- Including underlying request in errors ([#830](https://github.com/axios/axios/pull/830))
- Convert `method` to lowercase ([#930](https://github.com/axios/axios/pull/930))
### 0.16.1 (Apr 8, 2017)
- Improving HTTP adapter to return last request in case of redirects ([#828](https://github.com/axios/axios/pull/828))
- Updating `follow-redirects` dependency ([#829](https://github.com/axios/axios/pull/829))
- Adding support for passing `Buffer` in node ([#773](https://github.com/axios/axios/pull/773))
### 0.16.0 (Mar 31, 2017)
- **BREAKING** Removing `Promise` from axios typings in favor of built-in type declarations ([#480](https://github.com/axios/axios/issues/480))
- Adding `options` shortcut method ([#461](https://github.com/axios/axios/pull/461))
- Fixing issue with using `responseType: 'json'` in browsers incompatible with XHR Level 2 ([#654](https://github.com/axios/axios/pull/654))
- Improving React Native detection ([#731](https://github.com/axios/axios/pull/731))
- Fixing `combineURLs` to support empty `relativeURL` ([#581](https://github.com/axios/axios/pull/581))
- Removing `PROTECTION_PREFIX` support ([#561](https://github.com/axios/axios/pull/561))
### 0.15.3 (Nov 27, 2016)
- Fixing issue with custom instances and global defaults ([#443](https://github.com/axios/axios/issues/443))
- Renaming `axios.d.ts` to `index.d.ts` ([#519](https://github.com/axios/axios/issues/519))
- Adding `get`, `head`, and `delete` to `defaults.headers` ([#509](https://github.com/axios/axios/issues/509))
- Fixing issue with `btoa` and IE ([#507](https://github.com/axios/axios/issues/507))
- Adding support for proxy authentication ([#483](https://github.com/axios/axios/pull/483))
- Improving HTTP adapter to use `http` protocol by default ([#493](https://github.com/axios/axios/pull/493))
- Fixing proxy issues ([#491](https://github.com/axios/axios/pull/491))
### 0.15.2 (Oct 17, 2016)
- Fixing issue with calling `cancel` after response has been received ([#482](https://github.com/axios/axios/issues/482))
### 0.15.1 (Oct 14, 2016)
- Fixing issue with UMD ([#485](https://github.com/axios/axios/issues/485))
### 0.15.0 (Oct 10, 2016)
- Adding cancellation support ([#452](https://github.com/axios/axios/pull/452))
- Moving default adapter to global defaults ([#437](https://github.com/axios/axios/pull/437))
- Fixing issue with `file` URI scheme ([#440](https://github.com/axios/axios/pull/440))
- Fixing issue with `params` objects that have no prototype ([#445](https://github.com/axios/axios/pull/445))
### 0.14.0 (Aug 27, 2016)
- **BREAKING** Updating TypeScript definitions ([#419](https://github.com/axios/axios/pull/419))
- **BREAKING** Replacing `agent` option with `httpAgent` and `httpsAgent` ([#387](https://github.com/axios/axios/pull/387))
- **BREAKING** Splitting `progress` event handlers into `onUploadProgress` and `onDownloadProgress` ([#423](https://github.com/axios/axios/pull/423))
- Adding support for `http_proxy` and `https_proxy` environment variables ([#366](https://github.com/axios/axios/pull/366))
- Fixing issue with `auth` config option and `Authorization` header ([#397](https://github.com/axios/axios/pull/397))
- Don't set XSRF header if `xsrfCookieName` is `null` ([#406](https://github.com/axios/axios/pull/406))
### 0.13.1 (Jul 16, 2016)
- Fixing issue with response data not being transformed on error ([#378](https://github.com/axios/axios/issues/378))
### 0.13.0 (Jul 13, 2016)
- **BREAKING** Improved error handling ([#345](https://github.com/axios/axios/pull/345))
- **BREAKING** Response transformer now invoked in dispatcher not adapter ([10eb238](https://github.com/axios/axios/commit/10eb23865101f9347570552c04e9d6211376e25e))
- **BREAKING** Request adapters now return a `Promise` ([157efd5](https://github.com/axios/axios/commit/157efd5615890301824e3121cc6c9d2f9b21f94a))
- Fixing issue with `withCredentials` not being overwritten ([#343](https://github.com/axios/axios/issues/343))
- Fixing regression with request transformer being called before request interceptor ([#352](https://github.com/axios/axios/issues/352))
- Fixing custom instance defaults ([#341](https://github.com/axios/axios/issues/341))
- Fixing instances created from `axios.create` to have same API as default axios ([#217](https://github.com/axios/axios/issues/217))
### 0.12.0 (May 31, 2016)
- Adding support for `URLSearchParams` ([#317](https://github.com/axios/axios/pull/317))
- Adding `maxRedirects` option ([#307](https://github.com/axios/axios/pull/307))
### 0.11.1 (May 17, 2016)
- Fixing IE CORS support ([#313](https://github.com/axios/axios/pull/313))
- Fixing detection of `FormData` ([#325](https://github.com/axios/axios/pull/325))
- Adding `Axios` class to exports ([#321](https://github.com/axios/axios/pull/321))
### 0.11.0 (Apr 26, 2016)
- Adding support for Stream with HTTP adapter ([#296](https://github.com/axios/axios/pull/296))
- Adding support for custom HTTP status code error ranges ([#308](https://github.com/axios/axios/pull/308))
- Fixing issue with ArrayBuffer ([#299](https://github.com/axios/axios/pull/299))
### 0.10.0 (Apr 20, 2016)
- Fixing issue with some requests sending `undefined` instead of `null` ([#250](https://github.com/axios/axios/pull/250))
- Fixing basic auth for HTTP adapter ([#252](https://github.com/axios/axios/pull/252))
- Fixing request timeout for XHR adapter ([#227](https://github.com/axios/axios/pull/227))
- Fixing IE8 support by using `onreadystatechange` instead of `onload` ([#249](https://github.com/axios/axios/pull/249))
- Fixing IE9 cross domain requests ([#251](https://github.com/axios/axios/pull/251))
- Adding `maxContentLength` option ([#275](https://github.com/axios/axios/pull/275))
- Fixing XHR support for WebWorker environment ([#279](https://github.com/axios/axios/pull/279))
- Adding request instance to response ([#200](https://github.com/axios/axios/pull/200))
### 0.9.1 (Jan 24, 2016)
- Improving handling of request timeout in node ([#124](https://github.com/axios/axios/issues/124))
- Fixing network errors not rejecting ([#205](https://github.com/axios/axios/pull/205))
- Fixing issue with IE rejecting on HTTP 204 ([#201](https://github.com/axios/axios/issues/201))
- Fixing host/port when following redirects ([#198](https://github.com/axios/axios/pull/198))
### 0.9.0 (Jan 18, 2016)
- Adding support for custom adapters
- Fixing Content-Type header being removed when data is false ([#195](https://github.com/axios/axios/pull/195))
- Improving XDomainRequest implementation ([#185](https://github.com/axios/axios/pull/185))
- Improving config merging and order of precedence ([#183](https://github.com/axios/axios/pull/183))
- Fixing XDomainRequest support for only <= IE9 ([#182](https://github.com/axios/axios/pull/182))
### 0.8.1 (Dec 14, 2015)
- Adding support for passing XSRF token for cross domain requests when using `withCredentials` ([#168](https://github.com/axios/axios/pull/168))
- Fixing error with format of basic auth header ([#178](https://github.com/axios/axios/pull/173))
- Fixing error with JSON payloads throwing `InvalidStateError` in some cases ([#174](https://github.com/axios/axios/pull/174))
### 0.8.0 (Dec 11, 2015)
- Adding support for creating instances of axios ([#123](https://github.com/axios/axios/pull/123))
- Fixing http adapter to use `Buffer` instead of `String` in case of `responseType === 'arraybuffer'` ([#128](https://github.com/axios/axios/pull/128))
- Adding support for using custom parameter serializer with `paramsSerializer` option ([#121](https://github.com/axios/axios/pull/121))
- Fixing issue in IE8 caused by `forEach` on `arguments` ([#127](https://github.com/axios/axios/pull/127))
- Adding support for following redirects in node ([#146](https://github.com/axios/axios/pull/146))
- Adding support for transparent decompression if `content-encoding` is set ([#149](https://github.com/axios/axios/pull/149))
- Adding support for transparent XDomainRequest to handle cross domain requests in IE9 ([#140](https://github.com/axios/axios/pull/140))
- Adding support for HTTP basic auth via Authorization header ([#167](https://github.com/axios/axios/pull/167))
- Adding support for baseURL option ([#160](https://github.com/axios/axios/pull/160))
### 0.7.0 (Sep 29, 2015)
- Fixing issue with minified bundle in IE8 ([#87](https://github.com/axios/axios/pull/87))
- Adding support for passing agent in node ([#102](https://github.com/axios/axios/pull/102))
- Adding support for returning result from `axios.spread` for chaining ([#106](https://github.com/axios/axios/pull/106))
- Fixing typescript definition ([#105](https://github.com/axios/axios/pull/105))
- Fixing default timeout config for node ([#112](https://github.com/axios/axios/pull/112))
- Adding support for use in web workers, and react-native ([#70](https://github.com/axios/axios/issue/70)), ([#98](https://github.com/axios/axios/pull/98))
- Adding support for fetch like API `axios(url[, config])` ([#116](https://github.com/axios/axios/issues/116))
### 0.6.0 (Sep 21, 2015)
- Removing deprecated success/error aliases
- Fixing issue with array params not being properly encoded ([#49](https://github.com/axios/axios/pull/49))
- Fixing issue with User-Agent getting overridden ([#69](https://github.com/axios/axios/issues/69))
- Adding support for timeout config ([#56](https://github.com/axios/axios/issues/56))
- Removing es6-promise dependency
- Fixing issue preventing `length` to be used as a parameter ([#91](https://github.com/axios/axios/pull/91))
- Fixing issue with IE8 ([#85](https://github.com/axios/axios/pull/85))
- Converting build to UMD
### 0.5.4 (Apr 08, 2015)
- Fixing issue with FormData not being sent ([#53](https://github.com/axios/axios/issues/53))
### 0.5.3 (Apr 07, 2015)
- Using JSON.parse unconditionally when transforming response string ([#55](https://github.com/axios/axios/issues/55))
### 0.5.2 (Mar 13, 2015)
- Adding support for `statusText` in response ([#46](https://github.com/axios/axios/issues/46))
### 0.5.1 (Mar 10, 2015)
- Fixing issue using strict mode ([#45](https://github.com/axios/axios/issues/45))
- Fixing issue with standalone build ([#47](https://github.com/axios/axios/issues/47))
### 0.5.0 (Jan 23, 2015)
- Adding support for intercepetors ([#14](https://github.com/axios/axios/issues/14))
- Updating es6-promise dependency
### 0.4.2 (Dec 10, 2014)
- Fixing issue with `Content-Type` when using `FormData` ([#22](https://github.com/axios/axios/issues/22))
- Adding support for TypeScript ([#25](https://github.com/axios/axios/issues/25))
- Fixing issue with standalone build ([#29](https://github.com/axios/axios/issues/29))
- Fixing issue with verbs needing to be capitalized in some browsers ([#30](https://github.com/axios/axios/issues/30))
### 0.4.1 (Oct 15, 2014)
- Adding error handling to request for node.js ([#18](https://github.com/axios/axios/issues/18))
### 0.4.0 (Oct 03, 2014)
- Adding support for `ArrayBuffer` and `ArrayBufferView` ([#10](https://github.com/axios/axios/issues/10))
- Adding support for utf-8 for node.js ([#13](https://github.com/axios/axios/issues/13))
- Adding support for SSL for node.js ([#12](https://github.com/axios/axios/issues/12))
- Fixing incorrect `Content-Type` header ([#9](https://github.com/axios/axios/issues/9))
- Adding standalone build without bundled es6-promise ([#11](https://github.com/axios/axios/issues/11))
- Deprecating `success`/`error` in favor of `then`/`catch`
### 0.3.1 (Sep 16, 2014)
- Fixing missing post body when using node.js ([#3](https://github.com/axios/axios/issues/3))
### 0.3.0 (Sep 16, 2014)
- Fixing `success` and `error` to properly receive response data as individual arguments ([#8](https://github.com/axios/axios/issues/8))
- Updating `then` and `catch` to receive response data as a single object ([#6](https://github.com/axios/axios/issues/6))
- Fixing issue with `all` not working ([#7](https://github.com/axios/axios/issues/7))
### 0.2.2 (Sep 14, 2014)
- Fixing bundling with browserify ([#4](https://github.com/axios/axios/issues/4))
### 0.2.1 (Sep 12, 2014)
- Fixing build problem causing ridiculous file sizes
### 0.2.0 (Sep 12, 2014)
- Adding support for `all` and `spread`
- Adding support for node.js ([#1](https://github.com/axios/axios/issues/1))
### 0.1.0 (Aug 29, 2014)
- Initial release

View File

@ -1,19 +0,0 @@
Copyright (c) 2014-present Matt Zabriskie
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,800 +0,0 @@
# axios
[![npm version](https://img.shields.io/npm/v/axios.svg?style=flat-square)](https://www.npmjs.org/package/axios)
[![CDNJS](https://img.shields.io/cdnjs/v/axios.svg?style=flat-square)](https://cdnjs.com/libraries/axios)
[![build status](https://img.shields.io/travis/axios/axios/master.svg?style=flat-square)](https://travis-ci.org/axios/axios)
[![code coverage](https://img.shields.io/coveralls/mzabriskie/axios.svg?style=flat-square)](https://coveralls.io/r/mzabriskie/axios)
[![install size](https://packagephobia.now.sh/badge?p=axios)](https://packagephobia.now.sh/result?p=axios)
[![npm downloads](https://img.shields.io/npm/dm/axios.svg?style=flat-square)](http://npm-stat.com/charts.html?package=axios)
[![gitter chat](https://img.shields.io/gitter/room/mzabriskie/axios.svg?style=flat-square)](https://gitter.im/mzabriskie/axios)
[![code helpers](https://www.codetriage.com/axios/axios/badges/users.svg)](https://www.codetriage.com/axios/axios)
Promise based HTTP client for the browser and node.js
## Table of Contents
- [Features](#features)
- [Browser Support](#browser-support)
- [Installing](#installing)
- [Example](#example)
- [Axios API](#axios-api)
- [Request method aliases](#request-method-aliases)
- [Concurrency (Deprecated)](#concurrency-deprecated)
- [Creating an instance](#creating-an-instance)
- [Instance methods](#instance-methods)
- [Request Config](#request-config)
- [Response Schema](#response-schema)
- [Config Defaults](#config-defaults)
- [Global axios defaults](#global-axios-defaults)
- [Custom instance defaults](#custom-instance-defaults)
- [Config order of precedence](#config-order-of-precedence)
- [Interceptors](#interceptors)
- [Handling Errors](#handling-errors)
- [Cancellation](#cancellation)
- [Using application/x-www-form-urlencoded format](#using-applicationx-www-form-urlencoded-format)
- [Browser](#browser)
- [Node.js](#nodejs)
- [Query string](#query-string)
- [Form data](#form-data)
- [Semver](#semver)
- [Promises](#promises)
- [TypeScript](#typescript)
- [Resources](#resources)
- [Credits](#credits)
- [License](#license)
## Features
- Make [XMLHttpRequests](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) from the browser
- Make [http](http://nodejs.org/api/http.html) requests from node.js
- Supports the [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) API
- Intercept request and response
- Transform request and response data
- Cancel requests
- Automatic transforms for JSON data
- Client side support for protecting against [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
## Browser Support
![Chrome](https://raw.github.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png) | ![Firefox](https://raw.github.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png) | ![Safari](https://raw.github.com/alrra/browser-logos/master/src/safari/safari_48x48.png) | ![Opera](https://raw.github.com/alrra/browser-logos/master/src/opera/opera_48x48.png) | ![Edge](https://raw.github.com/alrra/browser-logos/master/src/edge/edge_48x48.png) | ![IE](https://raw.github.com/alrra/browser-logos/master/src/archive/internet-explorer_9-11/internet-explorer_9-11_48x48.png) |
--- | --- | --- | --- | --- | --- |
Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ | 11 ✔ |
[![Browser Matrix](https://saucelabs.com/open_sauce/build_matrix/axios.svg)](https://saucelabs.com/u/axios)
## Installing
Using npm:
```bash
$ npm install axios
```
Using bower:
```bash
$ bower install axios
```
Using yarn:
```bash
$ yarn add axios
```
Using jsDelivr CDN:
```html
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
```
Using unpkg CDN:
```html
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
```
## Example
### note: CommonJS usage
In order to gain the TypeScript typings (for intellisense / autocomplete) while using CommonJS imports with `require()` use the following approach:
```js
const axios = require('axios').default;
// axios.<method> will now provide autocomplete and parameter typings
```
Performing a `GET` request
```js
const axios = require('axios');
// Make a request for a user with a given ID
axios.get('/user?ID=12345')
.then(function (response) {
// handle success
console.log(response);
})
.catch(function (error) {
// handle error
console.log(error);
})
.then(function () {
// always executed
});
// Optionally the request above could also be done as
axios.get('/user', {
params: {
ID: 12345
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
})
.then(function () {
// always executed
});
// Want to use async/await? Add the `async` keyword to your outer function/method.
async function getUser() {
try {
const response = await axios.get('/user?ID=12345');
console.log(response);
} catch (error) {
console.error(error);
}
}
```
> **NOTE:** `async/await` is part of ECMAScript 2017 and is not supported in Internet
> Explorer and older browsers, so use with caution.
Performing a `POST` request
```js
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
```
Performing multiple concurrent requests
```js
function getUserAccount() {
return axios.get('/user/12345');
}
function getUserPermissions() {
return axios.get('/user/12345/permissions');
}
Promise.all([getUserAccount(), getUserPermissions()])
.then(function (results) {
const acct = results[0];
const perm = results[1];
});
```
## axios API
Requests can be made by passing the relevant config to `axios`.
##### axios(config)
```js
// Send a POST request
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
});
```
```js
// GET request for remote image in node.js
axios({
method: 'get',
url: 'http://bit.ly/2mTM3nY',
responseType: 'stream'
})
.then(function (response) {
response.data.pipe(fs.createWriteStream('ada_lovelace.jpg'))
});
```
##### axios(url[, config])
```js
// Send a GET request (default method)
axios('/user/12345');
```
### Request method aliases
For convenience aliases have been provided for all supported request methods.
##### axios.request(config)
##### axios.get(url[, config])
##### axios.delete(url[, config])
##### axios.head(url[, config])
##### axios.options(url[, config])
##### axios.post(url[, data[, config]])
##### axios.put(url[, data[, config]])
##### axios.patch(url[, data[, config]])
###### NOTE
When using the alias methods `url`, `method`, and `data` properties don't need to be specified in config.
### Concurrency (Deprecated)
Please use `Promise.all` to replace the below functions.
Helper functions for dealing with concurrent requests.
axios.all(iterable)
axios.spread(callback)
### Creating an instance
You can create a new instance of axios with a custom config.
##### axios.create([config])
```js
const instance = axios.create({
baseURL: 'https://some-domain.com/api/',
timeout: 1000,
headers: {'X-Custom-Header': 'foobar'}
});
```
### Instance methods
The available instance methods are listed below. The specified config will be merged with the instance config.
##### axios#request(config)
##### axios#get(url[, config])
##### axios#delete(url[, config])
##### axios#head(url[, config])
##### axios#options(url[, config])
##### axios#post(url[, data[, config]])
##### axios#put(url[, data[, config]])
##### axios#patch(url[, data[, config]])
##### axios#getUri([config])
## Request Config
These are the available config options for making requests. Only the `url` is required. Requests will default to `GET` if `method` is not specified.
```js
{
// `url` is the server URL that will be used for the request
url: '/user',
// `method` is the request method to be used when making the request
method: 'get', // default
// `baseURL` will be prepended to `url` unless `url` is absolute.
// It can be convenient to set `baseURL` for an instance of axios to pass relative URLs
// to methods of that instance.
baseURL: 'https://some-domain.com/api/',
// `transformRequest` allows changes to the request data before it is sent to the server
// This is only applicable for request methods 'PUT', 'POST', 'PATCH' and 'DELETE'
// The last function in the array must return a string or an instance of Buffer, ArrayBuffer,
// FormData or Stream
// You may modify the headers object.
transformRequest: [function (data, headers) {
// Do whatever you want to transform the data
return data;
}],
// `transformResponse` allows changes to the response data to be made before
// it is passed to then/catch
transformResponse: [function (data) {
// Do whatever you want to transform the data
return data;
}],
// `headers` are custom headers to be sent
headers: {'X-Requested-With': 'XMLHttpRequest'},
// `params` are the URL parameters to be sent with the request
// Must be a plain object or a URLSearchParams object
params: {
ID: 12345
},
// `paramsSerializer` is an optional function in charge of serializing `params`
// (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
paramsSerializer: function (params) {
return Qs.stringify(params, {arrayFormat: 'brackets'})
},
// `data` is the data to be sent as the request body
// Only applicable for request methods 'PUT', 'POST', 'DELETE , and 'PATCH'
// When no `transformRequest` is set, must be of one of the following types:
// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
// - Browser only: FormData, File, Blob
// - Node only: Stream, Buffer
data: {
firstName: 'Fred'
},
// syntax alternative to send data into the body
// method post
// only the value is sent, not the key
data: 'Country=Brasil&City=Belo Horizonte',
// `timeout` specifies the number of milliseconds before the request times out.
// If the request takes longer than `timeout`, the request will be aborted.
timeout: 1000, // default is `0` (no timeout)
// `withCredentials` indicates whether or not cross-site Access-Control requests
// should be made using credentials
withCredentials: false, // default
// `adapter` allows custom handling of requests which makes testing easier.
// Return a promise and supply a valid response (see lib/adapters/README.md).
adapter: function (config) {
/* ... */
},
// `auth` indicates that HTTP Basic auth should be used, and supplies credentials.
// This will set an `Authorization` header, overwriting any existing
// `Authorization` custom headers you have set using `headers`.
// Please note that only HTTP Basic auth is configurable through this parameter.
// For Bearer tokens and such, use `Authorization` custom headers instead.
auth: {
username: 'janedoe',
password: 's00pers3cret'
},
// `responseType` indicates the type of data that the server will respond with
// options are: 'arraybuffer', 'document', 'json', 'text', 'stream'
// browser only: 'blob'
responseType: 'json', // default
// `responseEncoding` indicates encoding to use for decoding responses (Node.js only)
// Note: Ignored for `responseType` of 'stream' or client-side requests
responseEncoding: 'utf8', // default
// `xsrfCookieName` is the name of the cookie to use as a value for xsrf token
xsrfCookieName: 'XSRF-TOKEN', // default
// `xsrfHeaderName` is the name of the http header that carries the xsrf token value
xsrfHeaderName: 'X-XSRF-TOKEN', // default
// `onUploadProgress` allows handling of progress events for uploads
// browser only
onUploadProgress: function (progressEvent) {
// Do whatever you want with the native progress event
},
// `onDownloadProgress` allows handling of progress events for downloads
// browser only
onDownloadProgress: function (progressEvent) {
// Do whatever you want with the native progress event
},
// `maxContentLength` defines the max size of the http response content in bytes allowed in node.js
maxContentLength: 2000,
// `maxBodyLength` (Node only option) defines the max size of the http request content in bytes allowed
maxBodyLength: 2000,
// `validateStatus` defines whether to resolve or reject the promise for a given
// HTTP response status code. If `validateStatus` returns `true` (or is set to `null`
// or `undefined`), the promise will be resolved; otherwise, the promise will be
// rejected.
validateStatus: function (status) {
return status >= 200 && status < 300; // default
},
// `maxRedirects` defines the maximum number of redirects to follow in node.js.
// If set to 0, no redirects will be followed.
maxRedirects: 5, // default
// `socketPath` defines a UNIX Socket to be used in node.js.
// e.g. '/var/run/docker.sock' to send requests to the docker daemon.
// Only either `socketPath` or `proxy` can be specified.
// If both are specified, `socketPath` is used.
socketPath: null, // default
// `httpAgent` and `httpsAgent` define a custom agent to be used when performing http
// and https requests, respectively, in node.js. This allows options to be added like
// `keepAlive` that are not enabled by default.
httpAgent: new http.Agent({ keepAlive: true }),
httpsAgent: new https.Agent({ keepAlive: true }),
// `proxy` defines the hostname, port, and protocol of the proxy server.
// You can also define your proxy using the conventional `http_proxy` and
// `https_proxy` environment variables. If you are using environment variables
// for your proxy configuration, you can also define a `no_proxy` environment
// variable as a comma-separated list of domains that should not be proxied.
// Use `false` to disable proxies, ignoring environment variables.
// `auth` indicates that HTTP Basic auth should be used to connect to the proxy, and
// supplies credentials.
// This will set an `Proxy-Authorization` header, overwriting any existing
// `Proxy-Authorization` custom headers you have set using `headers`.
// If the proxy server uses HTTPS, then you must set the protocol to `https`.
proxy: {
protocol: 'https',
host: '127.0.0.1',
port: 9000,
auth: {
username: 'mikeymike',
password: 'rapunz3l'
}
},
// `cancelToken` specifies a cancel token that can be used to cancel the request
// (see Cancellation section below for details)
cancelToken: new CancelToken(function (cancel) {
}),
// `decompress` indicates whether or not the response body should be decompressed
// automatically. If set to `true` will also remove the 'content-encoding' header
// from the responses objects of all decompressed responses
// - Node only (XHR cannot turn off decompression)
decompress: true // default
}
```
## Response Schema
The response for a request contains the following information.
```js
{
// `data` is the response that was provided by the server
data: {},
// `status` is the HTTP status code from the server response
status: 200,
// `statusText` is the HTTP status message from the server response
statusText: 'OK',
// `headers` the HTTP headers that the server responded with
// All header names are lower cased and can be accessed using the bracket notation.
// Example: `response.headers['content-type']`
headers: {},
// `config` is the config that was provided to `axios` for the request
config: {},
// `request` is the request that generated this response
// It is the last ClientRequest instance in node.js (in redirects)
// and an XMLHttpRequest instance in the browser
request: {}
}
```
When using `then`, you will receive the response as follows:
```js
axios.get('/user/12345')
.then(function (response) {
console.log(response.data);
console.log(response.status);
console.log(response.statusText);
console.log(response.headers);
console.log(response.config);
});
```
When using `catch`, or passing a [rejection callback](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then) as second parameter of `then`, the response will be available through the `error` object as explained in the [Handling Errors](#handling-errors) section.
## Config Defaults
You can specify config defaults that will be applied to every request.
### Global axios defaults
```js
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
```
### Custom instance defaults
```js
// Set config defaults when creating the instance
const instance = axios.create({
baseURL: 'https://api.example.com'
});
// Alter defaults after instance has been created
instance.defaults.headers.common['Authorization'] = AUTH_TOKEN;
```
### Config order of precedence
Config will be merged with an order of precedence. The order is library defaults found in [lib/defaults.js](https://github.com/axios/axios/blob/master/lib/defaults.js#L28), then `defaults` property of the instance, and finally `config` argument for the request. The latter will take precedence over the former. Here's an example.
```js
// Create an instance using the config defaults provided by the library
// At this point the timeout config value is `0` as is the default for the library
const instance = axios.create();
// Override timeout default for the library
// Now all requests using this instance will wait 2.5 seconds before timing out
instance.defaults.timeout = 2500;
// Override timeout for this request as it's known to take a long time
instance.get('/longRequest', {
timeout: 5000
});
```
## Interceptors
You can intercept requests or responses before they are handled by `then` or `catch`.
```js
// Add a request interceptor
axios.interceptors.request.use(function (config) {
// Do something before request is sent
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
// Add a response interceptor
axios.interceptors.response.use(function (response) {
// Any status code that lie within the range of 2xx cause this function to trigger
// Do something with response data
return response;
}, function (error) {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
return Promise.reject(error);
});
```
If you need to remove an interceptor later you can.
```js
const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);
```
You can add interceptors to a custom instance of axios.
```js
const instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});
```
## Handling Errors
```js
axios.get('/user/12345')
.catch(function (error) {
if (error.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.log(error.request);
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error', error.message);
}
console.log(error.config);
});
```
Using the `validateStatus` config option, you can define HTTP code(s) that should throw an error.
```js
axios.get('/user/12345', {
validateStatus: function (status) {
return status < 500; // Resolve only if the status code is less than 500
}
})
```
Using `toJSON` you get an object with more information about the HTTP error.
```js
axios.get('/user/12345')
.catch(function (error) {
console.log(error.toJSON());
});
```
## Cancellation
You can cancel a request using a *cancel token*.
> The axios cancel token API is based on the withdrawn [cancelable promises proposal](https://github.com/tc39/proposal-cancelable-promises).
You can create a cancel token using the `CancelToken.source` factory as shown below:
```js
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.get('/user/12345', {
cancelToken: source.token
}).catch(function (thrown) {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
// handle error
}
});
axios.post('/user/12345', {
name: 'new name'
}, {
cancelToken: source.token
})
// cancel the request (the message parameter is optional)
source.cancel('Operation canceled by the user.');
```
You can also create a cancel token by passing an executor function to the `CancelToken` constructor:
```js
const CancelToken = axios.CancelToken;
let cancel;
axios.get('/user/12345', {
cancelToken: new CancelToken(function executor(c) {
// An executor function receives a cancel function as a parameter
cancel = c;
})
});
// cancel the request
cancel();
```
> Note: you can cancel several requests with the same cancel token.
## Using application/x-www-form-urlencoded format
By default, axios serializes JavaScript objects to `JSON`. To send data in the `application/x-www-form-urlencoded` format instead, you can use one of the following options.
### Browser
In a browser, you can use the [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) API as follows:
```js
const params = new URLSearchParams();
params.append('param1', 'value1');
params.append('param2', 'value2');
axios.post('/foo', params);
```
> Note that `URLSearchParams` is not supported by all browsers (see [caniuse.com](http://www.caniuse.com/#feat=urlsearchparams)), but there is a [polyfill](https://github.com/WebReflection/url-search-params) available (make sure to polyfill the global environment).
Alternatively, you can encode data using the [`qs`](https://github.com/ljharb/qs) library:
```js
const qs = require('qs');
axios.post('/foo', qs.stringify({ 'bar': 123 }));
```
Or in another way (ES6),
```js
import qs from 'qs';
const data = { 'bar': 123 };
const options = {
method: 'POST',
headers: { 'content-type': 'application/x-www-form-urlencoded' },
data: qs.stringify(data),
url,
};
axios(options);
```
### Node.js
#### Query string
In node.js, you can use the [`querystring`](https://nodejs.org/api/querystring.html) module as follows:
```js
const querystring = require('querystring');
axios.post('http://something.com/', querystring.stringify({ foo: 'bar' }));
```
or ['URLSearchParams'](https://nodejs.org/api/url.html#url_class_urlsearchparams) from ['url module'](https://nodejs.org/api/url.html) as follows:
```js
const url = require('url');
const params = new url.URLSearchParams({ foo: 'bar' });
axios.post('http://something.com/', params.toString());
```
You can also use the [`qs`](https://github.com/ljharb/qs) library.
###### NOTE
The `qs` library is preferable if you need to stringify nested objects, as the `querystring` method has known issues with that use case (https://github.com/nodejs/node-v0.x-archive/issues/1665).
#### Form data
In node.js, you can use the [`form-data`](https://github.com/form-data/form-data) library as follows:
```js
const FormData = require('form-data');
const form = new FormData();
form.append('my_field', 'my value');
form.append('my_buffer', new Buffer(10));
form.append('my_file', fs.createReadStream('/foo/bar.jpg'));
axios.post('https://example.com', form, { headers: form.getHeaders() })
```
Alternatively, use an interceptor:
```js
axios.interceptors.request.use(config => {
if (config.data instanceof FormData) {
Object.assign(config.headers, config.data.getHeaders());
}
return config;
});
```
## Semver
Until axios reaches a `1.0` release, breaking changes will be released with a new minor version. For example `0.5.1`, and `0.5.4` will have the same API, but `0.6.0` will have breaking changes.
## Promises
axios depends on a native ES6 Promise implementation to be [supported](http://caniuse.com/promises).
If your environment doesn't support ES6 Promises, you can [polyfill](https://github.com/jakearchibald/es6-promise).
## TypeScript
axios includes [TypeScript](http://typescriptlang.org) definitions.
```typescript
import axios from 'axios';
axios.get('/user?ID=12345');
```
## Resources
* [Changelog](https://github.com/axios/axios/blob/master/CHANGELOG.md)
* [Upgrade Guide](https://github.com/axios/axios/blob/master/UPGRADE_GUIDE.md)
* [Ecosystem](https://github.com/axios/axios/blob/master/ECOSYSTEM.md)
* [Contributing Guide](https://github.com/axios/axios/blob/master/CONTRIBUTING.md)
* [Code of Conduct](https://github.com/axios/axios/blob/master/CODE_OF_CONDUCT.md)
## Credits
axios is heavily inspired by the [$http service](https://docs.angularjs.org/api/ng/service/$http) provided in [Angular](https://angularjs.org/). Ultimately axios is an effort to provide a standalone `$http`-like service for use outside of Angular.
## License
[MIT](LICENSE)

View File

@ -1,162 +0,0 @@
# Upgrade Guide
### 0.15.x -> 0.16.0
#### `Promise` Type Declarations
The `Promise` type declarations have been removed from the axios typings in favor of the built-in type declarations. If you use axios in a TypeScript project that targets `ES5`, please make sure to include the `es2015.promise` lib. Please see [this post](https://blog.mariusschulz.com/2016/11/25/typescript-2-0-built-in-type-declarations) for details.
### 0.13.x -> 0.14.0
#### TypeScript Definitions
The axios TypeScript definitions have been updated to match the axios API and use the ES2015 module syntax.
Please use the following `import` statement to import axios in TypeScript:
```typescript
import axios from 'axios';
axios.get('/foo')
.then(response => console.log(response))
.catch(error => console.log(error));
```
#### `agent` Config Option
The `agent` config option has been replaced with two new options: `httpAgent` and `httpsAgent`. Please use them instead.
```js
{
// Define a custom agent for HTTP
httpAgent: new http.Agent({ keepAlive: true }),
// Define a custom agent for HTTPS
httpsAgent: new https.Agent({ keepAlive: true })
}
```
#### `progress` Config Option
The `progress` config option has been replaced with the `onUploadProgress` and `onDownloadProgress` options.
```js
{
// Define a handler for upload progress events
onUploadProgress: function (progressEvent) {
// ...
},
// Define a handler for download progress events
onDownloadProgress: function (progressEvent) {
// ...
}
}
```
### 0.12.x -> 0.13.0
The `0.13.0` release contains several changes to custom adapters and error handling.
#### Error Handling
Previous to this release an error could either be a server response with bad status code or an actual `Error`. With this release Promise will always reject with an `Error`. In the case that a response was received, the `Error` will also include the response.
```js
axios.get('/user/12345')
.catch((error) => {
console.log(error.message);
console.log(error.code); // Not always specified
console.log(error.config); // The config that was used to make the request
console.log(error.response); // Only available if response was received from the server
});
```
#### Request Adapters
This release changes a few things about how request adapters work. Please take note if you are using your own custom adapter.
1. Response transformer is now called outside of adapter.
2. Request adapter returns a `Promise`.
This means that you no longer need to invoke `transformData` on response data. You will also no longer receive `resolve` and `reject` as arguments in your adapter.
Previous code:
```js
function myAdapter(resolve, reject, config) {
var response = {
data: transformData(
responseData,
responseHeaders,
config.transformResponse
),
status: request.status,
statusText: request.statusText,
headers: responseHeaders
};
settle(resolve, reject, response);
}
```
New code:
```js
function myAdapter(config) {
return new Promise(function (resolve, reject) {
var response = {
data: responseData,
status: request.status,
statusText: request.statusText,
headers: responseHeaders
};
settle(resolve, reject, response);
});
}
```
See the related commits for more details:
- [Response transformers](https://github.com/axios/axios/commit/10eb23865101f9347570552c04e9d6211376e25e)
- [Request adapter Promise](https://github.com/axios/axios/commit/157efd5615890301824e3121cc6c9d2f9b21f94a)
### 0.5.x -> 0.6.0
The `0.6.0` release contains mostly bug fixes, but there are a couple things to be aware of when upgrading.
#### ES6 Promise Polyfill
Up until the `0.6.0` release ES6 `Promise` was being polyfilled using [es6-promise](https://github.com/jakearchibald/es6-promise). With this release, the polyfill has been removed, and you will need to supply it yourself if your environment needs it.
```js
require('es6-promise').polyfill();
var axios = require('axios');
```
This will polyfill the global environment, and only needs to be done once.
#### `axios.success`/`axios.error`
The `success`, and `error` aliases were deprecated in [0.4.0](https://github.com/axios/axios/blob/master/CHANGELOG.md#040-oct-03-2014). As of this release they have been removed entirely. Instead please use `axios.then`, and `axios.catch` respectively.
```js
axios.get('some/url')
.then(function (res) {
/* ... */
})
.catch(function (err) {
/* ... */
});
```
#### UMD
Previous versions of axios shipped with an AMD, CommonJS, and Global build. This has all been rolled into a single UMD build.
```js
// AMD
require(['bower_components/axios/dist/axios'], function (axios) {
/* ... */
});
// CommonJS
var axios = require('axios/dist/axios');
```

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,161 +0,0 @@
export interface AxiosTransformer {
(data: any, headers?: any): any;
}
export interface AxiosAdapter {
(config: AxiosRequestConfig): AxiosPromise<any>;
}
export interface AxiosBasicCredentials {
username: string;
password: string;
}
export interface AxiosProxyConfig {
host: string;
port: number;
auth?: {
username: string;
password:string;
};
protocol?: string;
}
export type Method =
| 'get' | 'GET'
| 'delete' | 'DELETE'
| 'head' | 'HEAD'
| 'options' | 'OPTIONS'
| 'post' | 'POST'
| 'put' | 'PUT'
| 'patch' | 'PATCH'
| 'purge' | 'PURGE'
| 'link' | 'LINK'
| 'unlink' | 'UNLINK'
export type ResponseType =
| 'arraybuffer'
| 'blob'
| 'document'
| 'json'
| 'text'
| 'stream'
export interface AxiosRequestConfig {
url?: string;
method?: Method;
baseURL?: string;
transformRequest?: AxiosTransformer | AxiosTransformer[];
transformResponse?: AxiosTransformer | AxiosTransformer[];
headers?: any;
params?: any;
paramsSerializer?: (params: any) => string;
data?: any;
timeout?: number;
timeoutErrorMessage?: string;
withCredentials?: boolean;
adapter?: AxiosAdapter;
auth?: AxiosBasicCredentials;
responseType?: ResponseType;
xsrfCookieName?: string;
xsrfHeaderName?: string;
onUploadProgress?: (progressEvent: any) => void;
onDownloadProgress?: (progressEvent: any) => void;
maxContentLength?: number;
validateStatus?: ((status: number) => boolean) | null;
maxBodyLength?: number;
maxRedirects?: number;
socketPath?: string | null;
httpAgent?: any;
httpsAgent?: any;
proxy?: AxiosProxyConfig | false;
cancelToken?: CancelToken;
decompress?: boolean;
}
export interface AxiosResponse<T = any> {
data: T;
status: number;
statusText: string;
headers: any;
config: AxiosRequestConfig;
request?: any;
}
export interface AxiosError<T = any> extends Error {
config: AxiosRequestConfig;
code?: string;
request?: any;
response?: AxiosResponse<T>;
isAxiosError: boolean;
toJSON: () => object;
}
export interface AxiosPromise<T = any> extends Promise<AxiosResponse<T>> {
}
export interface CancelStatic {
new (message?: string): Cancel;
}
export interface Cancel {
message: string;
}
export interface Canceler {
(message?: string): void;
}
export interface CancelTokenStatic {
new (executor: (cancel: Canceler) => void): CancelToken;
source(): CancelTokenSource;
}
export interface CancelToken {
promise: Promise<Cancel>;
reason?: Cancel;
throwIfRequested(): void;
}
export interface CancelTokenSource {
token: CancelToken;
cancel: Canceler;
}
export interface AxiosInterceptorManager<V> {
use(onFulfilled?: (value: V) => V | Promise<V>, onRejected?: (error: any) => any): number;
eject(id: number): void;
}
export interface AxiosInstance {
(config: AxiosRequestConfig): AxiosPromise;
(url: string, config?: AxiosRequestConfig): AxiosPromise;
defaults: AxiosRequestConfig;
interceptors: {
request: AxiosInterceptorManager<AxiosRequestConfig>;
response: AxiosInterceptorManager<AxiosResponse>;
};
getUri(config?: AxiosRequestConfig): string;
request<T = any, R = AxiosResponse<T>> (config: AxiosRequestConfig): Promise<R>;
get<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>;
delete<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>;
head<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>;
options<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>;
post<T = any, R = AxiosResponse<T>>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R>;
put<T = any, R = AxiosResponse<T>>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R>;
patch<T = any, R = AxiosResponse<T>>(url: string, data?: any, config?: AxiosRequestConfig): Promise<R>;
}
export interface AxiosStatic extends AxiosInstance {
create(config?: AxiosRequestConfig): AxiosInstance;
Cancel: CancelStatic;
CancelToken: CancelTokenStatic;
isCancel(value: any): boolean;
all<T>(values: (T | Promise<T>)[]): Promise<T[]>;
spread<T, R>(callback: (...args: T[]) => R): (array: T[]) => R;
isAxiosError(payload: any): payload is AxiosError;
}
declare const axios: AxiosStatic;
export default axios;

View File

@ -1 +0,0 @@
module.exports = require('./lib/axios');

View File

@ -1,37 +0,0 @@
# axios // adapters
The modules under `adapters/` are modules that handle dispatching a request and settling a returned `Promise` once a response is received.
## Example
```js
var settle = require('./../core/settle');
module.exports = function myAdapter(config) {
// At this point:
// - config has been merged with defaults
// - request transformers have already run
// - request interceptors have already run
// Make the request using config provided
// Upon response settle the Promise
return new Promise(function(resolve, reject) {
var response = {
data: responseData,
status: request.status,
statusText: request.statusText,
headers: responseHeaders,
config: config,
request: request
};
settle(resolve, reject, response);
// From here:
// - response transformers will run
// - response interceptors will run
});
}
```

View File

@ -1,303 +0,0 @@
'use strict';
var utils = require('./../utils');
var settle = require('./../core/settle');
var buildFullPath = require('../core/buildFullPath');
var buildURL = require('./../helpers/buildURL');
var http = require('http');
var https = require('https');
var httpFollow = require('follow-redirects').http;
var httpsFollow = require('follow-redirects').https;
var url = require('url');
var zlib = require('zlib');
var pkg = require('./../../package.json');
var createError = require('../core/createError');
var enhanceError = require('../core/enhanceError');
var isHttps = /https:?/;
/**
*
* @param {http.ClientRequestArgs} options
* @param {AxiosProxyConfig} proxy
* @param {string} location
*/
function setProxy(options, proxy, location) {
options.hostname = proxy.host;
options.host = proxy.host;
options.port = proxy.port;
options.path = location;
// Basic proxy authorization
if (proxy.auth) {
var base64 = Buffer.from(proxy.auth.username + ':' + proxy.auth.password, 'utf8').toString('base64');
options.headers['Proxy-Authorization'] = 'Basic ' + base64;
}
// If a proxy is used, any redirects must also pass through the proxy
options.beforeRedirect = function beforeRedirect(redirection) {
redirection.headers.host = redirection.host;
setProxy(redirection, proxy, redirection.href);
};
}
/*eslint consistent-return:0*/
module.exports = function httpAdapter(config) {
return new Promise(function dispatchHttpRequest(resolvePromise, rejectPromise) {
var resolve = function resolve(value) {
resolvePromise(value);
};
var reject = function reject(value) {
rejectPromise(value);
};
var data = config.data;
var headers = config.headers;
// Set User-Agent (required by some servers)
// Only set header if it hasn't been set in config
// See https://github.com/axios/axios/issues/69
if (!headers['User-Agent'] && !headers['user-agent']) {
headers['User-Agent'] = 'axios/' + pkg.version;
}
if (data && !utils.isStream(data)) {
if (Buffer.isBuffer(data)) {
// Nothing to do...
} else if (utils.isArrayBuffer(data)) {
data = Buffer.from(new Uint8Array(data));
} else if (utils.isString(data)) {
data = Buffer.from(data, 'utf-8');
} else {
return reject(createError(
'Data after transformation must be a string, an ArrayBuffer, a Buffer, or a Stream',
config
));
}
// Add Content-Length header if data exists
headers['Content-Length'] = data.length;
}
// HTTP basic authentication
var auth = undefined;
if (config.auth) {
var username = config.auth.username || '';
var password = config.auth.password || '';
auth = username + ':' + password;
}
// Parse url
var fullPath = buildFullPath(config.baseURL, config.url);
var parsed = url.parse(fullPath);
var protocol = parsed.protocol || 'http:';
if (!auth && parsed.auth) {
var urlAuth = parsed.auth.split(':');
var urlUsername = urlAuth[0] || '';
var urlPassword = urlAuth[1] || '';
auth = urlUsername + ':' + urlPassword;
}
if (auth) {
delete headers.Authorization;
}
var isHttpsRequest = isHttps.test(protocol);
var agent = isHttpsRequest ? config.httpsAgent : config.httpAgent;
var options = {
path: buildURL(parsed.path, config.params, config.paramsSerializer).replace(/^\?/, ''),
method: config.method.toUpperCase(),
headers: headers,
agent: agent,
agents: { http: config.httpAgent, https: config.httpsAgent },
auth: auth
};
if (config.socketPath) {
options.socketPath = config.socketPath;
} else {
options.hostname = parsed.hostname;
options.port = parsed.port;
}
var proxy = config.proxy;
if (!proxy && proxy !== false) {
var proxyEnv = protocol.slice(0, -1) + '_proxy';
var proxyUrl = process.env[proxyEnv] || process.env[proxyEnv.toUpperCase()];
if (proxyUrl) {
var parsedProxyUrl = url.parse(proxyUrl);
var noProxyEnv = process.env.no_proxy || process.env.NO_PROXY;
var shouldProxy = true;
if (noProxyEnv) {
var noProxy = noProxyEnv.split(',').map(function trim(s) {
return s.trim();
});
shouldProxy = !noProxy.some(function proxyMatch(proxyElement) {
if (!proxyElement) {
return false;
}
if (proxyElement === '*') {
return true;
}
if (proxyElement[0] === '.' &&
parsed.hostname.substr(parsed.hostname.length - proxyElement.length) === proxyElement) {
return true;
}
return parsed.hostname === proxyElement;
});
}
if (shouldProxy) {
proxy = {
host: parsedProxyUrl.hostname,
port: parsedProxyUrl.port,
protocol: parsedProxyUrl.protocol
};
if (parsedProxyUrl.auth) {
var proxyUrlAuth = parsedProxyUrl.auth.split(':');
proxy.auth = {
username: proxyUrlAuth[0],
password: proxyUrlAuth[1]
};
}
}
}
}
if (proxy) {
options.headers.host = parsed.hostname + (parsed.port ? ':' + parsed.port : '');
setProxy(options, proxy, protocol + '//' + parsed.hostname + (parsed.port ? ':' + parsed.port : '') + options.path);
}
var transport;
var isHttpsProxy = isHttpsRequest && (proxy ? isHttps.test(proxy.protocol) : true);
if (config.transport) {
transport = config.transport;
} else if (config.maxRedirects === 0) {
transport = isHttpsProxy ? https : http;
} else {
if (config.maxRedirects) {
options.maxRedirects = config.maxRedirects;
}
transport = isHttpsProxy ? httpsFollow : httpFollow;
}
if (config.maxBodyLength > -1) {
options.maxBodyLength = config.maxBodyLength;
}
// Create the request
var req = transport.request(options, function handleResponse(res) {
if (req.aborted) return;
// uncompress the response body transparently if required
var stream = res;
// return the last request in case of redirects
var lastRequest = res.req || req;
// if no content, is HEAD request or decompress disabled we should not decompress
if (res.statusCode !== 204 && lastRequest.method !== 'HEAD' && config.decompress !== false) {
switch (res.headers['content-encoding']) {
/*eslint default-case:0*/
case 'gzip':
case 'compress':
case 'deflate':
// add the unzipper to the body stream processing pipeline
stream = stream.pipe(zlib.createUnzip());
// remove the content-encoding in order to not confuse downstream operations
delete res.headers['content-encoding'];
break;
}
}
var response = {
status: res.statusCode,
statusText: res.statusMessage,
headers: res.headers,
config: config,
request: lastRequest
};
if (config.responseType === 'stream') {
response.data = stream;
settle(resolve, reject, response);
} else {
var responseBuffer = [];
stream.on('data', function handleStreamData(chunk) {
responseBuffer.push(chunk);
// make sure the content length is not over the maxContentLength if specified
if (config.maxContentLength > -1 && Buffer.concat(responseBuffer).length > config.maxContentLength) {
stream.destroy();
reject(createError('maxContentLength size of ' + config.maxContentLength + ' exceeded',
config, null, lastRequest));
}
});
stream.on('error', function handleStreamError(err) {
if (req.aborted) return;
reject(enhanceError(err, config, null, lastRequest));
});
stream.on('end', function handleStreamEnd() {
var responseData = Buffer.concat(responseBuffer);
if (config.responseType !== 'arraybuffer') {
responseData = responseData.toString(config.responseEncoding);
if (!config.responseEncoding || config.responseEncoding === 'utf8') {
responseData = utils.stripBOM(responseData);
}
}
response.data = responseData;
settle(resolve, reject, response);
});
}
});
// Handle errors
req.on('error', function handleRequestError(err) {
if (req.aborted && err.code !== 'ERR_FR_TOO_MANY_REDIRECTS') return;
reject(enhanceError(err, config, null, req));
});
// Handle request timeout
if (config.timeout) {
// Sometime, the response will be very slow, and does not respond, the connect event will be block by event loop system.
// And timer callback will be fired, and abort() will be invoked before connection, then get "socket hang up" and code ECONNRESET.
// At this time, if we have a large number of request, nodejs will hang up some socket on background. and the number will up and up.
// And then these socket which be hang up will devoring CPU little by little.
// ClientRequest.setTimeout will be fired on the specify milliseconds, and can make sure that abort() will be fired after connect.
req.setTimeout(config.timeout, function handleRequestTimeout() {
req.abort();
reject(createError('timeout of ' + config.timeout + 'ms exceeded', config, 'ECONNABORTED', req));
});
}
if (config.cancelToken) {
// Handle cancellation
config.cancelToken.promise.then(function onCanceled(cancel) {
if (req.aborted) return;
req.abort();
reject(cancel);
});
}
// Send the request
if (utils.isStream(data)) {
data.on('error', function handleStreamError(err) {
reject(enhanceError(err, config, null, req));
}).pipe(req);
} else {
req.end(data);
}
});
};

View File

@ -1,179 +0,0 @@
'use strict';
var utils = require('./../utils');
var settle = require('./../core/settle');
var cookies = require('./../helpers/cookies');
var buildURL = require('./../helpers/buildURL');
var buildFullPath = require('../core/buildFullPath');
var parseHeaders = require('./../helpers/parseHeaders');
var isURLSameOrigin = require('./../helpers/isURLSameOrigin');
var createError = require('../core/createError');
module.exports = function xhrAdapter(config) {
return new Promise(function dispatchXhrRequest(resolve, reject) {
var requestData = config.data;
var requestHeaders = config.headers;
if (utils.isFormData(requestData)) {
delete requestHeaders['Content-Type']; // Let the browser set it
}
var request = new XMLHttpRequest();
// HTTP basic authentication
if (config.auth) {
var username = config.auth.username || '';
var password = config.auth.password ? unescape(encodeURIComponent(config.auth.password)) : '';
requestHeaders.Authorization = 'Basic ' + btoa(username + ':' + password);
}
var fullPath = buildFullPath(config.baseURL, config.url);
request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true);
// Set the request timeout in MS
request.timeout = config.timeout;
// Listen for ready state
request.onreadystatechange = function handleLoad() {
if (!request || request.readyState !== 4) {
return;
}
// The request errored out and we didn't get a response, this will be
// handled by onerror instead
// With one exception: request that using file: protocol, most browsers
// will return status as 0 even though it's a successful request
if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)) {
return;
}
// Prepare the response
var responseHeaders = 'getAllResponseHeaders' in request ? parseHeaders(request.getAllResponseHeaders()) : null;
var responseData = !config.responseType || config.responseType === 'text' ? request.responseText : request.response;
var response = {
data: responseData,
status: request.status,
statusText: request.statusText,
headers: responseHeaders,
config: config,
request: request
};
settle(resolve, reject, response);
// Clean up request
request = null;
};
// Handle browser request cancellation (as opposed to a manual cancellation)
request.onabort = function handleAbort() {
if (!request) {
return;
}
reject(createError('Request aborted', config, 'ECONNABORTED', request));
// Clean up request
request = null;
};
// Handle low level network errors
request.onerror = function handleError() {
// Real errors are hidden from us by the browser
// onerror should only fire if it's a network error
reject(createError('Network Error', config, null, request));
// Clean up request
request = null;
};
// Handle timeout
request.ontimeout = function handleTimeout() {
var timeoutErrorMessage = 'timeout of ' + config.timeout + 'ms exceeded';
if (config.timeoutErrorMessage) {
timeoutErrorMessage = config.timeoutErrorMessage;
}
reject(createError(timeoutErrorMessage, config, 'ECONNABORTED',
request));
// Clean up request
request = null;
};
// Add xsrf header
// This is only done if running in a standard browser environment.
// Specifically not if we're in a web worker, or react-native.
if (utils.isStandardBrowserEnv()) {
// Add xsrf header
var xsrfValue = (config.withCredentials || isURLSameOrigin(fullPath)) && config.xsrfCookieName ?
cookies.read(config.xsrfCookieName) :
undefined;
if (xsrfValue) {
requestHeaders[config.xsrfHeaderName] = xsrfValue;
}
}
// Add headers to the request
if ('setRequestHeader' in request) {
utils.forEach(requestHeaders, function setRequestHeader(val, key) {
if (typeof requestData === 'undefined' && key.toLowerCase() === 'content-type') {
// Remove Content-Type if data is undefined
delete requestHeaders[key];
} else {
// Otherwise add header to the request
request.setRequestHeader(key, val);
}
});
}
// Add withCredentials to request if needed
if (!utils.isUndefined(config.withCredentials)) {
request.withCredentials = !!config.withCredentials;
}
// Add responseType to request if needed
if (config.responseType) {
try {
request.responseType = config.responseType;
} catch (e) {
// Expected DOMException thrown by browsers not compatible XMLHttpRequest Level 2.
// But, this can be suppressed for 'json' type as it can be parsed by default 'transformResponse' function.
if (config.responseType !== 'json') {
throw e;
}
}
}
// Handle progress if needed
if (typeof config.onDownloadProgress === 'function') {
request.addEventListener('progress', config.onDownloadProgress);
}
// Not all browsers support upload events
if (typeof config.onUploadProgress === 'function' && request.upload) {
request.upload.addEventListener('progress', config.onUploadProgress);
}
if (config.cancelToken) {
// Handle cancellation
config.cancelToken.promise.then(function onCanceled(cancel) {
if (!request) {
return;
}
request.abort();
reject(cancel);
// Clean up request
request = null;
});
}
if (!requestData) {
requestData = null;
}
// Send the request
request.send(requestData);
});
};

View File

@ -1,56 +0,0 @@
'use strict';
var utils = require('./utils');
var bind = require('./helpers/bind');
var Axios = require('./core/Axios');
var mergeConfig = require('./core/mergeConfig');
var defaults = require('./defaults');
/**
* Create an instance of Axios
*
* @param {Object} defaultConfig The default config for the instance
* @return {Axios} A new instance of Axios
*/
function createInstance(defaultConfig) {
var context = new Axios(defaultConfig);
var instance = bind(Axios.prototype.request, context);
// Copy axios.prototype to instance
utils.extend(instance, Axios.prototype, context);
// Copy context to instance
utils.extend(instance, context);
return instance;
}
// Create the default instance to be exported
var axios = createInstance(defaults);
// Expose Axios class to allow class inheritance
axios.Axios = Axios;
// Factory for creating new instances
axios.create = function create(instanceConfig) {
return createInstance(mergeConfig(axios.defaults, instanceConfig));
};
// Expose Cancel & CancelToken
axios.Cancel = require('./cancel/Cancel');
axios.CancelToken = require('./cancel/CancelToken');
axios.isCancel = require('./cancel/isCancel');
// Expose all/spread
axios.all = function all(promises) {
return Promise.all(promises);
};
axios.spread = require('./helpers/spread');
// Expose isAxiosError
axios.isAxiosError = require('./helpers/isAxiosError');
module.exports = axios;
// Allow use of default import syntax in TypeScript
module.exports.default = axios;

View File

@ -1,19 +0,0 @@
'use strict';
/**
* A `Cancel` is an object that is thrown when an operation is canceled.
*
* @class
* @param {string=} message The message.
*/
function Cancel(message) {
this.message = message;
}
Cancel.prototype.toString = function toString() {
return 'Cancel' + (this.message ? ': ' + this.message : '');
};
Cancel.prototype.__CANCEL__ = true;
module.exports = Cancel;

View File

@ -1,57 +0,0 @@
'use strict';
var Cancel = require('./Cancel');
/**
* A `CancelToken` is an object that can be used to request cancellation of an operation.
*
* @class
* @param {Function} executor The executor function.
*/
function CancelToken(executor) {
if (typeof executor !== 'function') {
throw new TypeError('executor must be a function.');
}
var resolvePromise;
this.promise = new Promise(function promiseExecutor(resolve) {
resolvePromise = resolve;
});
var token = this;
executor(function cancel(message) {
if (token.reason) {
// Cancellation has already been requested
return;
}
token.reason = new Cancel(message);
resolvePromise(token.reason);
});
}
/**
* Throws a `Cancel` if cancellation has been requested.
*/
CancelToken.prototype.throwIfRequested = function throwIfRequested() {
if (this.reason) {
throw this.reason;
}
};
/**
* Returns an object that contains a new `CancelToken` and a function that, when called,
* cancels the `CancelToken`.
*/
CancelToken.source = function source() {
var cancel;
var token = new CancelToken(function executor(c) {
cancel = c;
});
return {
token: token,
cancel: cancel
};
};
module.exports = CancelToken;

View File

@ -1,5 +0,0 @@
'use strict';
module.exports = function isCancel(value) {
return !!(value && value.__CANCEL__);
};

View File

@ -1,95 +0,0 @@
'use strict';
var utils = require('./../utils');
var buildURL = require('../helpers/buildURL');
var InterceptorManager = require('./InterceptorManager');
var dispatchRequest = require('./dispatchRequest');
var mergeConfig = require('./mergeConfig');
/**
* Create a new instance of Axios
*
* @param {Object} instanceConfig The default config for the instance
*/
function Axios(instanceConfig) {
this.defaults = instanceConfig;
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager()
};
}
/**
* Dispatch a request
*
* @param {Object} config The config specific for this request (merged with this.defaults)
*/
Axios.prototype.request = function request(config) {
/*eslint no-param-reassign:0*/
// Allow for axios('example/url'[, config]) a la fetch API
if (typeof config === 'string') {
config = arguments[1] || {};
config.url = arguments[0];
} else {
config = config || {};
}
config = mergeConfig(this.defaults, config);
// Set config.method
if (config.method) {
config.method = config.method.toLowerCase();
} else if (this.defaults.method) {
config.method = this.defaults.method.toLowerCase();
} else {
config.method = 'get';
}
// Hook up interceptors middleware
var chain = [dispatchRequest, undefined];
var promise = Promise.resolve(config);
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
chain.unshift(interceptor.fulfilled, interceptor.rejected);
});
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
chain.push(interceptor.fulfilled, interceptor.rejected);
});
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
return promise;
};
Axios.prototype.getUri = function getUri(config) {
config = mergeConfig(this.defaults, config);
return buildURL(config.url, config.params, config.paramsSerializer).replace(/^\?/, '');
};
// Provide aliases for supported request methods
utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
/*eslint func-names:0*/
Axios.prototype[method] = function(url, config) {
return this.request(mergeConfig(config || {}, {
method: method,
url: url,
data: (config || {}).data
}));
};
});
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
/*eslint func-names:0*/
Axios.prototype[method] = function(url, data, config) {
return this.request(mergeConfig(config || {}, {
method: method,
url: url,
data: data
}));
};
});
module.exports = Axios;

View File

@ -1,52 +0,0 @@
'use strict';
var utils = require('./../utils');
function InterceptorManager() {
this.handlers = [];
}
/**
* Add a new interceptor to the stack
*
* @param {Function} fulfilled The function to handle `then` for a `Promise`
* @param {Function} rejected The function to handle `reject` for a `Promise`
*
* @return {Number} An ID used to remove interceptor later
*/
InterceptorManager.prototype.use = function use(fulfilled, rejected) {
this.handlers.push({
fulfilled: fulfilled,
rejected: rejected
});
return this.handlers.length - 1;
};
/**
* Remove an interceptor from the stack
*
* @param {Number} id The ID that was returned by `use`
*/
InterceptorManager.prototype.eject = function eject(id) {
if (this.handlers[id]) {
this.handlers[id] = null;
}
};
/**
* Iterate over all the registered interceptors
*
* This method is particularly useful for skipping over any
* interceptors that may have become `null` calling `eject`.
*
* @param {Function} fn The function to call for each interceptor
*/
InterceptorManager.prototype.forEach = function forEach(fn) {
utils.forEach(this.handlers, function forEachHandler(h) {
if (h !== null) {
fn(h);
}
});
};
module.exports = InterceptorManager;

View File

@ -1,7 +0,0 @@
# axios // core
The modules found in `core/` should be modules that are specific to the domain logic of axios. These modules would most likely not make sense to be consumed outside of the axios module, as their logic is too specific. Some examples of core modules are:
- Dispatching requests
- Managing interceptors
- Handling config

Some files were not shown because too many files have changed in this diff Show More